Browse Source

added tests for ModuleCCSession class (with a fake Session object)
added a few function declarations in ccsession.h that were missing (but were already implemented in ccsession.cc)
fixed 1 bug in ccsession.cc, other ones are pending (tests already exist but commented out right now)


git-svn-id: svn://bind10.isc.org/svn/bind10/trunk@1359 e5f2f494-b856-4b98-b285-d166d9295462

Jelte Jansen 15 years ago
parent
commit
366177a393

+ 5 - 2
src/lib/config/ccsession.cc

@@ -213,6 +213,7 @@ ModuleCCSession::init(
     ) throw (isc::cc::SessionError)
 {
     module_specification_ = readModuleSpecification(spec_file_name);
+    setModuleSpec(module_specification_);
     sleep(1);
 
     module_name_ = module_specification_.getFullSpec()->get("module_name")->stringValue();
@@ -239,7 +240,7 @@ ModuleCCSession::init(
         std::cerr << "[" << module_name_ << "] Error in specification: " << answer << std::endl;
     }
     
-    config_ = Element::createFromString("{}");
+    setLocalConfig(Element::createFromString("{}"));
     // get any stored configuration from the manager
     if (config_handler_) {
         ElementPtr cmd = Element::createFromString("{ \"command\": [\"get_config\", {\"module_name\":\"" + module_name_ + "\"} ] }");
@@ -279,7 +280,9 @@ ModuleCCSession::handleConfigUpdate(ElementPtr new_config)
         int rcode;
         parseAnswer(rcode, answer);
         if (rcode == 0) {
-            isc::data::merge(config_, new_config);
+            ElementPtr local_config = getLocalConfig();
+            isc::data::merge(local_config, new_config);
+            setLocalConfig(local_config);
         }
     }
     return answer;

+ 9 - 5
src/lib/config/ccsession.h

@@ -33,6 +33,15 @@ class io_service;
 namespace isc {
 namespace config {
 
+ElementPtr createAnswer(const int rcode);
+ElementPtr createAnswer(const int rcode, const ElementPtr arg);
+ElementPtr createAnswer(const int rcode, const std::string& arg);
+ElementPtr parseAnswer(int &rcode, const ElementPtr msg);
+
+ElementPtr createCommand(const std::string& command, ElementPtr arg);
+const std::string parseCommand(ElementPtr& arg, const ElementPtr command);
+
+
 ///
 /// \brief A standard cc session exception that is thrown if a function
 /// is there is a problem with one of the messages
@@ -153,7 +162,6 @@ private:
     std::string module_name_;
     isc::cc::Session session_;
     ModuleSpec module_specification_;
-    isc::data::ElementPtr config_;
     ElementPtr handleConfigUpdate(ElementPtr new_config);
 
     isc::data::ElementPtr(*config_handler_)(isc::data::ElementPtr new_config);
@@ -163,10 +171,6 @@ private:
     void updateRemoteConfig(const std::string& module_name, ElementPtr new_config);
 };
 
-ElementPtr createAnswer(const int rcode);
-ElementPtr createAnswer(const int rcode, const ElementPtr arg);
-ElementPtr createAnswer(const int rcode, const std::string& arg);
-
 }
 }
 #endif // __CCSESSION_H

+ 10 - 3
src/lib/config/unittests/Makefile.am

@@ -2,15 +2,22 @@ AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/ext
 
 CLEANFILES = *.gcno *.gcda
 
+lib_LTLIBRARIES = libfake_session.la
+libfake_session_la_SOURCES = fake_session.h fake_session.cc
+
 TESTS =
 if HAVE_GTEST
 TESTS += run_unittests
-run_unittests_SOURCES = module_spec_unittests.cc config_data_unittests.cc run_unittests.cc
+#run_unittests_SOURCES = ccsession_unittests.cc module_spec_unittests.cc config_data_unittests.cc run_unittests.cc
+run_unittests_SOURCES = ccsession_unittests.cc run_unittests.cc
+
 run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
-run_unittests_LDADD =  $(top_builddir)/src/lib/config/libcfgclient.la $(GTEST_LDADD)
+run_unittests_LDADD =  $(GTEST_LDADD)
 run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
-run_unittests_LDADD += $(top_builddir)/src/lib/cc/libcc.a
+run_unittests_LDADD += $(top_builddir)/src/lib/config/libcfgclient.la
+run_unittests_LDADD += $(top_builddir)/src/lib/cc/data.o
+run_unittests_LDADD += libfake_session.la
 
 if HAVE_BOOSTLIB
 run_unittests_LDFLAGS += $(AM_LDFLAGS) $(BOOST_LDFLAGS)

File diff suppressed because it is too large
+ 343 - 0
src/lib/config/unittests/ccsession_unittests.cc


+ 269 - 0
src/lib/config/unittests/fake_session.cc

@@ -0,0 +1,269 @@
+// 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: session.cc 1250 2010-03-09 22:52:15Z jinmei $
+
+#include "config.h"
+
+#include <stdint.h>
+
+#include <cstdio>
+#include <vector>
+#include <iostream>
+#include <sstream>
+
+#ifdef HAVE_BOOSTLIB
+#include <boost/bind.hpp>
+#include <boost/function.hpp>
+#include <boost/asio.hpp>
+#endif
+
+#include <boost/foreach.hpp>
+
+#include <exceptions/exceptions.h>
+
+#include <cc/data.h>
+#include "fake_session.h"
+
+using namespace std;
+using namespace isc::cc;
+using namespace isc::data;
+
+#ifdef HAVE_BOOSTLIB
+// some of the boost::asio names conflict with socket API system calls
+// (e.g. write(2)) so we don't import the entire boost::asio namespace.
+using boost::asio::io_service;
+using boost::asio::ip::tcp;
+#endif
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+
+// ok i want these in cc/data 
+static bool
+listContains(ElementPtr list, ElementPtr el)
+{
+    BOOST_FOREACH(ElementPtr l_el, list->listValue()) {
+        if (l_el == el) {
+            return true;
+        }
+    }
+    return false;
+}
+
+static void
+listRemove(ElementPtr list, ElementPtr el) {
+    int i = -1;
+    BOOST_FOREACH(ElementPtr s_el, list->listValue()) {
+        if (el == s_el) {
+            i = 0;
+        }
+    }
+    if (i >= 0) {
+        list->remove(i);
+    }
+}
+// endwant
+
+ElementPtr
+getFirstMessage(std::string& group, std::string& to)
+{
+    ElementPtr el;
+    if (msg_queue && msg_queue->size() > 0) {
+        el = msg_queue->get(0);
+        msg_queue->remove(0);
+        group = el->get(0)->stringValue();
+        to = el->get(1)->stringValue();
+        return el->get(2);
+    } else {
+        group = "";
+        to = "";
+        return ElementPtr();
+    }
+}
+
+void
+addMessage(ElementPtr msg, const std::string& group, const std::string& to)
+{
+    ElementPtr m_el = Element::createFromString("[]");
+    m_el->add(Element::create(group));
+    m_el->add(Element::create(to));
+    m_el->add(msg);
+    if (!msg_queue) {
+        msg_queue = Element::createFromString("[]");
+    }
+    msg_queue->add(m_el);
+}
+
+bool
+haveSubscription(const std::string& group, const std::string& instance)
+{
+    ElementPtr s1 = Element::createFromString("[]");
+    ElementPtr s2 = Element::createFromString("[]");
+    s1->add(Element::create(group));
+    s1->add(Element::create(instance));
+    s2->add(Element::create(group));
+    s2->add(Element::create(instance));
+    return (listContains(subscriptions, s1) || listContains(subscriptions, s2));
+}
+
+bool
+haveSubscription(const ElementPtr group, const ElementPtr instance)
+{
+    return haveSubscription(group->stringValue(), instance->stringValue());
+}
+
+namespace isc {
+namespace cc {
+
+Session::Session()
+{
+}
+
+#ifdef HAVE_BOOSTLIB
+Session::Session(io_service& io_service UNUSED_PARAM)
+{
+}
+#endif
+
+Session::~Session() {
+}
+
+void
+Session::disconnect() {
+}
+
+int
+Session::getSocket() const {
+    return 1;
+}
+
+void
+Session::startRead(boost::function<void()> read_callback UNUSED_PARAM) {
+}
+
+void
+Session::establish() {
+}
+
+//
+// Convert to wire format and send this on the TCP stream with its length prefix
+//
+void
+Session::sendmsg(ElementPtr& msg) {
+    //cout << "[XX] client sends message: " << msg << endl;
+    // err, to where?
+    addMessage(msg, "*", "*");
+}
+
+void
+Session::sendmsg(ElementPtr& env, ElementPtr& msg) {
+    //cout << "[XX] client sends message: " << msg << endl;
+    //cout << "[XX] env: " << env << endl;
+    addMessage(msg, env->get("group")->stringValue(), env->get("to")->stringValue());
+}
+
+bool
+Session::recvmsg(ElementPtr& msg, bool nonblock UNUSED_PARAM) {
+    //cout << "[XX] client asks for message " << endl;
+    if (initial_messages &&
+        initial_messages->getType() == Element::list &&
+        initial_messages->size() > 0) {
+        msg = initial_messages->get(0);
+        initial_messages->remove(0);
+    } else {
+        msg = ElementPtr();
+    }
+    return (true);
+}
+
+bool
+Session::recvmsg(ElementPtr& env, ElementPtr& msg, bool nonblock UNUSED_PARAM) {
+    //cout << "[XX] client asks for message and env" << endl;
+    env = ElementPtr();
+    if (initial_messages &&
+        initial_messages->getType() == Element::list &&
+        initial_messages->size() > 0) {
+        // do we need initial message to have env[group] and [to] too?
+        msg = initial_messages->get(0);
+        initial_messages->remove(0);
+        return true;
+    } else {
+        BOOST_FOREACH(ElementPtr c_m, msg_queue->listValue()) {
+            ElementPtr to_remove = ElementPtr();
+            if (haveSubscription(c_m->get(0), c_m->get(1))) {
+                env = Element::createFromString("{}");
+                env->set("group", c_m->get(0));
+                env->set("to", c_m->get(1));
+                msg = c_m->get(2);
+                to_remove = c_m;
+            }
+            if (to_remove) {
+                listRemove(msg_queue, to_remove);
+                return true;
+            }
+        }
+    }
+    msg = ElementPtr();
+    env = ElementPtr();
+    return false;
+}
+
+void
+    //cout << "[XX] client subscribes to " << group << " . " << instance << endl;
+Session::subscribe(std::string group, std::string instance) {
+    ElementPtr s_el = Element::createFromString("[]");
+    s_el->add(Element::create(group));
+    s_el->add(Element::create(instance));
+    subscriptions->add(s_el);
+}
+
+void
+Session::unsubscribe(std::string group, std::string instance) {
+    //cout << "[XX] client unsubscribes from " << group << " . " << instance << endl;
+    ElementPtr s_el = Element::createFromString("[]");
+    s_el->add(Element::create(group));
+    s_el->add(Element::create(instance));
+    listRemove(subscriptions, s_el);
+}
+
+unsigned int
+Session::group_sendmsg(ElementPtr msg, std::string group,
+                       std::string to, std::string instance UNUSED_PARAM)
+{
+    //cout << "[XX] client sends message: " << msg << endl;
+    //cout << "[XX] to: " << group << " . " << instance << "." << to << endl;
+    addMessage(msg, group, to);
+    return 1;
+}
+
+bool
+Session::group_recvmsg(ElementPtr& envelope, ElementPtr& msg,
+                       bool nonblock)
+{
+    return (recvmsg(envelope, msg, nonblock));
+}
+
+unsigned int
+Session::reply(ElementPtr& envelope, ElementPtr& newmsg) {
+    //cout << "[XX] client sends reply: " << newmsg << endl;
+    //cout << "[XX] env: " << envelope << endl;
+    addMessage(newmsg, envelope->get("group")->stringValue(), envelope->get("to")->stringValue());
+    return 1;
+}
+
+}
+}

+ 108 - 0
src/lib/config/unittests/fake_session.h

@@ -0,0 +1,108 @@
+// 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: session.h 1250 2010-03-09 22:52:15Z jinmei $
+
+#ifndef _ISC_SESSION_H
+#define _ISC_SESSION_H 1
+
+#include <string>
+
+#include <boost/function.hpp>
+
+#include <exceptions/exceptions.h>
+
+#include <cc/data.h>
+
+namespace boost {
+namespace asio {
+class io_service;
+}
+}
+
+// global variables so tests can insert
+// update and check, before, during and after
+// the actual session object was created/destroyed
+
+// if initial_messages contains a list of messages,
+// these are sent when recv_msg or group_recvmsg is called
+// instead of whatever is in the msg queue
+isc::data::ElementPtr initial_messages;
+isc::data::ElementPtr subscriptions;
+isc::data::ElementPtr msg_queue;
+
+bool haveSubscription(const std::string& group, const std::string& instance);
+bool haveSubscription(const isc::data::ElementPtr group, const isc::data::ElementPtr instance);
+isc::data::ElementPtr getFirstMessage(std::string& group, std::string& to);
+void addMessage(isc::data::ElementPtr, const std::string& group, const std::string& to);
+
+namespace isc {
+    namespace cc {
+
+        class SessionError : public isc::Exception {
+        public:
+            SessionError(const char* file, size_t line, const char* what) :
+                isc::Exception(file, line, what) {}
+        };
+
+        class Session {
+        private:
+            Session(const Session& source);
+            Session& operator=(const Session& source);
+
+        public:
+            // public so tests can inspect them
+        
+            Session();
+            Session(boost::asio::io_service& ioservice);
+            ~Session();
+
+            // XXX: quick hack to allow the user to watch the socket directly.
+            int getSocket() const;
+
+            void startRead(boost::function<void()> read_callback);
+
+            void establish();
+            void disconnect();
+            void sendmsg(isc::data::ElementPtr& msg);
+            void sendmsg(isc::data::ElementPtr& env,
+                         isc::data::ElementPtr& msg);
+            bool recvmsg(isc::data::ElementPtr& msg,
+                         bool nonblock = true);
+            bool recvmsg(isc::data::ElementPtr& env,
+                         isc::data::ElementPtr& msg,
+                         bool nonblock = true);
+            void subscribe(std::string group,
+                           std::string instance = "*");
+            void unsubscribe(std::string group,
+                             std::string instance = "*");
+            unsigned 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);
+            unsigned int reply(isc::data::ElementPtr& envelope,
+                               isc::data::ElementPtr& newmsg);
+
+        };
+    } // namespace cc
+} // namespace isc
+
+#endif // _ISC_SESSION_H
+
+// Local Variables:
+// mode: c++
+// End: