Browse Source

introduced an abstract base Session class to allow tests to define and use a mock session class.
completed one notify test case using a mock session. it identified a bug in the main code so the test fails right now.


git-svn-id: svn://bind10.isc.org/svn/bind10/branches/trac221@2327 e5f2f494-b856-4b98-b285-d166d9295462

JINMEI Tatuya 15 years ago
parent
commit
d990b85fbe

+ 20 - 13
src/bin/auth/auth_srv.cc

@@ -55,6 +55,7 @@
 using namespace std;
 using namespace std;
 
 
 using namespace isc;
 using namespace isc;
+using namespace isc::cc;
 using namespace isc::datasrc;
 using namespace isc::datasrc;
 using namespace isc::dns;
 using namespace isc::dns;
 using namespace isc::dns::rdata;
 using namespace isc::dns::rdata;
@@ -69,7 +70,8 @@ private:
     AuthSrvImpl(const AuthSrvImpl& source);
     AuthSrvImpl(const AuthSrvImpl& source);
     AuthSrvImpl& operator=(const AuthSrvImpl& source);
     AuthSrvImpl& operator=(const AuthSrvImpl& source);
 public:
 public:
-    AuthSrvImpl(AbstractXfroutClient& xfrout_client);
+    AuthSrvImpl(AbstractSession& session_with_xfrin,
+                AbstractXfroutClient& xfrout_client);
     ~AuthSrvImpl();
     ~AuthSrvImpl();
     isc::data::ElementPtr setDbFile(const isc::data::ElementPtr config);
     isc::data::ElementPtr setDbFile(const isc::data::ElementPtr config);
 
 
@@ -90,7 +92,7 @@ public:
     bool verbose_mode_;
     bool verbose_mode_;
 
 
     bool is_notify_session_established_;
     bool is_notify_session_established_;
-    isc::cc::Session session_with_xfrin_;
+    AbstractSession& session_with_xfrin_;
 
 
     bool is_axfr_connection_established_;
     bool is_axfr_connection_established_;
     AbstractXfroutClient& xfrout_client_;
     AbstractXfroutClient& xfrout_client_;
@@ -99,9 +101,11 @@ public:
     static const uint16_t DEFAULT_LOCAL_UDPSIZE = 4096;
     static const uint16_t DEFAULT_LOCAL_UDPSIZE = 4096;
 };
 };
 
 
-AuthSrvImpl::AuthSrvImpl(AbstractXfroutClient& xfrout_client) :
+AuthSrvImpl::AuthSrvImpl(AbstractSession& session_with_xfrin,
+                         AbstractXfroutClient& xfrout_client) :
     cs_(NULL), verbose_mode_(false),
     cs_(NULL), verbose_mode_(false),
     is_notify_session_established_(false),
     is_notify_session_established_(false),
+    session_with_xfrin_(session_with_xfrin),
     is_axfr_connection_established_(false),
     is_axfr_connection_established_(false),
     xfrout_client_(xfrout_client)
     xfrout_client_(xfrout_client)
 {
 {
@@ -125,8 +129,9 @@ AuthSrvImpl::~AuthSrvImpl() {
     }
     }
 }
 }
 
 
-AuthSrv::AuthSrv(AbstractXfroutClient& xfrout_client) :
-    impl_(new AuthSrvImpl(xfrout_client))
+AuthSrv::AuthSrv(AbstractSession& session_with_xfrin,
+                 AbstractXfroutClient& xfrout_client) :
+    impl_(new AuthSrvImpl(session_with_xfrin, xfrout_client))
 {}
 {}
 
 
 AuthSrv::~AuthSrv() {
 AuthSrv::~AuthSrv() {
@@ -218,7 +223,8 @@ AuthSrv::processMessage(const IOMessage& io_message, Message& message,
         // Ignore all responses.
         // Ignore all responses.
         if (message.getHeaderFlag(MessageFlag::QR())) {
         if (message.getHeaderFlag(MessageFlag::QR())) {
             if (impl_->verbose_mode_) {
             if (impl_->verbose_mode_) {
-                cerr << "[b10-auth] received unexpected response, ignoring" << endl;
+                cerr << "[b10-auth] received unexpected response, ignoring"
+                     << endl;
             }
             }
             return (false);
             return (false);
         }
         }
@@ -231,8 +237,8 @@ AuthSrv::processMessage(const IOMessage& io_message, Message& message,
         message.fromWire(request_buffer);
         message.fromWire(request_buffer);
     } catch (const DNSProtocolError& error) {
     } catch (const DNSProtocolError& error) {
         if (impl_->verbose_mode_) {
         if (impl_->verbose_mode_) {
-            cerr << "[b10-auth] returning " <<  error.getRcode().toText() << ": "
-                 << error.what() << endl;
+            cerr << "[b10-auth] returning " <<  error.getRcode().toText()
+                 << ": " << error.what() << endl;
         }
         }
         makeErrorMessage(message, response_renderer, error.getRcode(),
         makeErrorMessage(message, response_renderer, error.getRcode(),
                          impl_->verbose_mode_);
                          impl_->verbose_mode_);
@@ -375,7 +381,7 @@ AuthSrvImpl::processNotify(const IOMessage& io_message, Message& message,
     // zone
     // zone
     if (!is_notify_session_established_) {
     if (!is_notify_session_established_) {
         try {
         try {
-            session_with_xfrin_.establish();
+            session_with_xfrin_.establish(NULL);
             is_notify_session_established_ = true;
             is_notify_session_established_ = true;
         } catch (const isc::cc::SessionError& err) {
         } catch (const isc::cc::SessionError& err) {
             if (verbose_mode_) {
             if (verbose_mode_) {
@@ -398,17 +404,18 @@ AuthSrvImpl::processNotify(const IOMessage& io_message, Message& message,
     try {
     try {
         ElementPtr notify_command = Element::createFromString(
         ElementPtr notify_command = Element::createFromString(
                 command_template_start + question->getName().toText() + 
                 command_template_start + question->getName().toText() + 
-                command_template_mid + remote_ip_address + command_template_end);
+                command_template_mid + remote_ip_address +
+                command_template_end);
         const unsigned int seq =
         const unsigned int seq =
-            session_with_xfrin_.group_sendmsg(notify_command, "Xfrin");
+            session_with_xfrin_.group_sendmsg(notify_command, "Xfrin",
+                                              "*", "*");
         ElementPtr env, answer;
         ElementPtr env, answer;
         session_with_xfrin_.group_recvmsg(env, answer, false, seq);
         session_with_xfrin_.group_recvmsg(env, answer, false, seq);
         int rcode;
         int rcode;
         parseAnswer(rcode, answer);
         parseAnswer(rcode, answer);
     } catch (const isc::data::ParseError &err) {
     } catch (const isc::data::ParseError &err) {
         if (verbose_mode_) {
         if (verbose_mode_) {
-            cerr << "create notfiy command failed: "
-                << err.what() << endl;
+            cerr << "create notfiy command failed: " << err.what() << endl;
         }
         }
         return (false);
         return (false);
     } catch (const isc::Exception& err) {
     } catch (const isc::Exception& err) {

+ 2 - 1
src/bin/auth/auth_srv.h

@@ -51,7 +51,8 @@ private:
     AuthSrv(const AuthSrv& source);
     AuthSrv(const AuthSrv& source);
     AuthSrv& operator=(const AuthSrv& source);
     AuthSrv& operator=(const AuthSrv& source);
 public:
 public:
-    explicit AuthSrv(isc::xfr::AbstractXfroutClient& xfrout_client);
+    AuthSrv(isc::cc::AbstractSession& session_with_xfrin,
+            isc::xfr::AbstractXfroutClient& xfrout_client);
     ~AuthSrv();
     ~AuthSrv();
     //@}
     //@}
     /// \return \c true if the \message contains a response to be returned;
     /// \return \c true if the \message contains a response to be returned;

+ 2 - 1
src/bin/auth/main.cc

@@ -137,6 +137,7 @@ main(int argc, char* argv[]) {
     // initialize command channel
     // initialize command channel
     int ret = 0;
     int ret = 0;
 
 
+    Session session_with_xfrin;
     XfroutClient xfrout_client(UNIX_SOCKET_FILE);
     XfroutClient xfrout_client(UNIX_SOCKET_FILE);
     try {
     try {
         string specfile;
         string specfile;
@@ -147,7 +148,7 @@ main(int argc, char* argv[]) {
             specfile = string(AUTH_SPECFILE_LOCATION);
             specfile = string(AUTH_SPECFILE_LOCATION);
         }
         }
 
 
-        auth_server = new AuthSrv(xfrout_client);
+        auth_server = new AuthSrv(session_with_xfrin, xfrout_client);
         auth_server->setVerbose(verbose_mode);
         auth_server->setVerbose(verbose_mode);
 
 
         io_service = new asio_link::IOService(auth_server, port, use_ipv4,
         io_service = new asio_link::IOService(auth_server, port, use_ipv4,

+ 54 - 2
src/bin/auth/tests/auth_srv_unittest.cc

@@ -26,6 +26,7 @@
 #include <dns/rrtype.h>
 #include <dns/rrtype.h>
 
 
 #include <cc/data.h>
 #include <cc/data.h>
+#include <cc/session.h>
 
 
 #include <xfr/xfrout_client.h>
 #include <xfr/xfrout_client.h>
 
 
@@ -36,6 +37,7 @@
 
 
 using isc::UnitTestUtil;
 using isc::UnitTestUtil;
 using namespace std;
 using namespace std;
+using namespace isc::cc;
 using namespace isc::dns;
 using namespace isc::dns;
 using namespace isc::data;
 using namespace isc::data;
 using namespace isc::xfr;
 using namespace isc::xfr;
@@ -72,8 +74,27 @@ private:
         bool send_ok_;
         bool send_ok_;
         bool disconnect_ok_;
         bool disconnect_ok_;
     };
     };
+
+    class MockSession : public AbstractSession {
+    public:
+        MockSession() :
+            // by default we return a simple "success" message.
+            msg_(Element::createFromString("{\"result\": [0, \"SUCCESS\"]}"))
+        {}
+        virtual void establish(const char* socket_file);
+        virtual void disconnect();
+        virtual int group_sendmsg(ElementPtr msg, string group,
+                                  string instance, string to);
+        virtual bool group_recvmsg(ElementPtr& envelope, ElementPtr& msg,
+                                   bool nonblock, int seq);
+        void setMessage(ElementPtr msg) { msg_ = msg; }
+    private:
+        ElementPtr msg_;
+    };
+
 protected:
 protected:
-    AuthSrvTest() : server(xfrout), request_message(Message::RENDER),
+    AuthSrvTest() : server(notify_session, xfrout),
+                    request_message(Message::RENDER),
                     parse_message(Message::PARSE), default_qid(0x1035),
                     parse_message(Message::PARSE), default_qid(0x1035),
                     opcode(Opcode(Opcode::QUERY())), qname("www.example.com"),
                     opcode(Opcode(Opcode::QUERY())), qname("www.example.com"),
                     qclass(RRClass::IN()), qtype(RRType::A()),
                     qclass(RRClass::IN()), qtype(RRType::A()),
@@ -85,6 +106,7 @@ protected:
         delete io_message;
         delete io_message;
         delete endpoint;
         delete endpoint;
     }
     }
+    MockSession notify_session;
     MockXfroutClient xfrout;
     MockXfroutClient xfrout;
     AuthSrv server;
     AuthSrv server;
     Message request_message;
     Message request_message;
@@ -109,6 +131,33 @@ protected:
 };
 };
 
 
 void
 void
+AuthSrvTest::MockSession::establish(const char* socket_file UNUSED_PARAM) {
+}
+
+void
+AuthSrvTest::MockSession::disconnect() {
+}
+
+int
+AuthSrvTest::MockSession::group_sendmsg(ElementPtr msg UNUSED_PARAM,
+                                        string group UNUSED_PARAM,
+                                        string instance UNUSED_PARAM,
+                                        string to UNUSED_PARAM)
+{
+    return (0);
+}
+
+bool
+AuthSrvTest::MockSession::group_recvmsg(ElementPtr& envelope UNUSED_PARAM,
+                                        ElementPtr& msg,
+                                        bool nonblock UNUSED_PARAM,
+                                        int seq UNUSED_PARAM)
+{
+    msg = msg_;
+    return (true);
+}
+
+void
 AuthSrvTest::MockXfroutClient::connect() {
 AuthSrvTest::MockXfroutClient::connect() {
     if (!connect_ok_) {
     if (!connect_ok_) {
         isc_throw(XfroutError, "xfrout connection disabled for test");
         isc_throw(XfroutError, "xfrout connection disabled for test");
@@ -137,6 +186,7 @@ AuthSrvTest::MockXfroutClient::sendXfroutRequestInfo(
     return (0);
     return (0);
 }
 }
 
 
+
 // These are flags to indicate whether the corresponding flag bit of the
 // 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
 // DNS header is to be set in the test cases.  (Note that the flag values
 // is irrelevant to their wire-format values)
 // is irrelevant to their wire-format values)
@@ -402,8 +452,10 @@ TEST_F(AuthSrvTest, AXFRDisconnectFail) {
 TEST_F(AuthSrvTest, notifyInTest) {
 TEST_F(AuthSrvTest, notifyInTest) {
     createRequest(Opcode::NOTIFY(), Name("example.com"), RRClass::IN(),
     createRequest(Opcode::NOTIFY(), Name("example.com"), RRClass::IN(),
                   RRType::SOA());
                   RRType::SOA());
-    EXPECT_EQ(false, server.processMessage(*io_message, parse_message,
+    EXPECT_EQ(true, server.processMessage(*io_message, parse_message,
                                            response_renderer));
                                            response_renderer));
+    headerCheck(parse_message, default_qid, Rcode::NOERROR(),
+                Opcode::NOTIFY().getCode(), QR_FLAG | AA_FLAG, 1, 0, 0, 0);
 }
 }
 
 
 void
 void

+ 47 - 11
src/lib/cc/session.h

@@ -40,7 +40,43 @@ namespace isc {
                 isc::Exception(file, line, what) {}
                 isc::Exception(file, line, what) {}
         };
         };
 
 
-        class Session {
+        /// \brief The AbstractSession class is an abstract base class that
+        /// defines the interfaces of Session.
+        /// The intended primary usage of abstraction is to allow tests for the
+        /// user class of Session without requiring actual communication
+        /// channels.
+        /// For simplicity we only define the methods that are necessary for
+        /// existing test cases that use this base class.  Eventually we'll
+        /// probably have to extend them.
+        class AbstractSession {
+            ///
+            /// \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:
+            AbstractSession(const AbstractSession& source);
+            AbstractSession& operator=(const AbstractSession& source);
+        protected:
+            AbstractSession() {}
+        public:
+            virtual ~AbstractSession() {}
+            //@}
+            virtual void establish(const char* socket_file) = 0;
+            virtual void disconnect() = 0;
+            virtual int group_sendmsg(isc::data::ElementPtr msg,
+                                      std::string group,
+                                      std::string instance,
+                                      std::string to) = 0;
+            virtual bool group_recvmsg(isc::data::ElementPtr& envelope,
+                                       isc::data::ElementPtr& msg,
+                                       bool nonblock,
+                                       int seq) = 0;
+        };
+
+    class Session : public AbstractSession {
         private:
         private:
             SessionImpl* impl_;
             SessionImpl* impl_;
 
 
@@ -51,14 +87,14 @@ namespace isc {
         public:
         public:
             Session();
             Session();
             Session(asio::io_service& ioservice);
             Session(asio::io_service& ioservice);
-            ~Session();
+            virtual ~Session();
 
 
             // XXX: quick hack to allow the user to watch the socket directly.
             // XXX: quick hack to allow the user to watch the socket directly.
             int getSocket() const;
             int getSocket() const;
 
 
             void startRead(boost::function<void()> read_callback);
             void startRead(boost::function<void()> read_callback);
 
 
-            void establish(const char* socket_file = NULL);
+            virtual void establish(const char* socket_file = NULL);
             void disconnect();
             void disconnect();
             void sendmsg(isc::data::ElementPtr& msg);
             void sendmsg(isc::data::ElementPtr& msg);
             void sendmsg(isc::data::ElementPtr& env,
             void sendmsg(isc::data::ElementPtr& env,
@@ -74,14 +110,14 @@ namespace isc {
                            std::string instance = "*");
                            std::string instance = "*");
             void unsubscribe(std::string group,
             void unsubscribe(std::string group,
                              std::string instance = "*");
                              std::string instance = "*");
-            int group_sendmsg(isc::data::ElementPtr msg,
-                                       std::string group,
-                                       std::string instance = "*",
-                                       std::string to = "*");
-            bool group_recvmsg(isc::data::ElementPtr& envelope,
-                               isc::data::ElementPtr& msg,
-                               bool nonblock = true,
-                               int seq = -1);
+            virtual int group_sendmsg(isc::data::ElementPtr msg,
+                                      std::string group,
+                                      std::string instance = "*",
+                                      std::string to = "*");
+            virtual bool group_recvmsg(isc::data::ElementPtr& envelope,
+                                       isc::data::ElementPtr& msg,
+                                       bool nonblock = true,
+                                       int seq = -1);
             int reply(isc::data::ElementPtr& envelope,
             int reply(isc::data::ElementPtr& envelope,
                                isc::data::ElementPtr& newmsg);
                                isc::data::ElementPtr& newmsg);
             bool hasQueuedMsgs();
             bool hasQueuedMsgs();