Browse Source

[1914] Basic tests for groupRecvMsgAsync

* Needed to extend the FakeSession::addMessage to hold the sequence
  number for representing answers.
* Clarified the recipient parameter - it is the group, instance is
  ignored, since it is not used anywhere in the code anyway.
* The tests simply register a callback and check it is called. More
  complex tests to come later.
Michal 'vorner' Vaner 13 years ago
parent
commit
4bdecaadf9

+ 6 - 4
src/lib/config/ccsession.h

@@ -420,10 +420,11 @@ public:
     /// In case the is_reply is false, the function looks for command messages.
     /// The seq parameter is ignored, but the recipient one is considered. If
     /// it is an empty string, any command is taken. If it is non-empty, only
-    /// commands addressed to the recipient channel are taken. This can be used
-    /// to receive foreign commands or notifications. In such case, it might
-    /// be desirable to call the groupRecvMsgAsync again from within the
-    /// callback, to receive any future commands or events of the same type.
+    /// commands addressed to the recipient channel (eg. group - instance is
+    /// ignored for now)are taken. This can be used to receive foreign commands
+    /// or notifications. In such case, it might be desirable to call the
+    /// groupRecvMsgAsync again from within the callback, to receive any future
+    /// commands or events of the same type.
     ///
     /// The interaction with other receiving functions is slightly complicated.
     /// The groupRecvMsg call takes precedence. If the message matches its
@@ -448,6 +449,7 @@ public:
     ///     command is good one.
     /// \return An identifier of the request. This will be passed to the
     ///     callback or can be used to cancel the request by cancelAsyncRecv.
+    /// \todo Decide what to do with instance and what was it meant for anyway.
     AsyncRecvRequestID groupRecvMsgAsync(const AsyncRecvCallback& callback,
                                          bool is_reply = true, int seq = -1,
                                          const std::string& recipient =

+ 116 - 2
src/lib/config/tests/ccsession_unittests.cc

@@ -27,11 +27,13 @@
 #include <log/logger_name.h>
 
 #include <boost/scoped_ptr.hpp>
+#include <boost/bind.hpp>
 
 using namespace isc::data;
 using namespace isc::config;
 using namespace isc::cc;
 using namespace std;
+using namespace boost;
 
 namespace {
 std::string
@@ -497,10 +499,10 @@ TEST_F(CCSessionTest, remoteConfig) {
         const size_t qsize(session.getMsgQueue()->size());
         EXPECT_TRUE(session.getMsgQueue()->get(qsize - 2)->equals(*el(
             "[ \"ConfigManager\", \"*\", { \"command\": ["
-            "\"get_module_spec\", { \"module_name\": \"Spec2\" } ] } ]")));
+            "\"get_module_spec\", { \"module_name\": \"Spec2\" } ] }, -1 ]")));
         EXPECT_TRUE(session.getMsgQueue()->get(qsize - 1)->equals(*el(
             "[ \"ConfigManager\", \"*\", { \"command\": [ \"get_config\","
-            "{ \"module_name\": \"Spec2\" } ] } ]")));
+            "{ \"module_name\": \"Spec2\" } ] }, -1 ]")));
         EXPECT_EQ("Spec2", module_name);
         // Since we returned an empty local config above, the default value
         // for "item1", which is 1, should be used.
@@ -709,6 +711,118 @@ TEST_F(CCSessionTest, doubleStartWithAddRemoteConfig) {
                  FakeSession::DoubleRead);
 }
 
+/// \brief Test fixture for asynchronous receiving of messages.
+///
+/// This is extension to the CCSessionTest. It would be possible to add
+/// the functionality to the CCSessionTest, but it is going to be used
+/// only by few tests and is non-trivial, so it is placed to a separate
+/// sub-class.
+class AsyncReceiveCCSessionTest : public CCSessionTest {
+protected:
+    AsyncReceiveCCSessionTest() :
+        mccs_(ccspecfile("spec29.spec"), session, NULL, NULL, false, false),
+        next_flag_(0)
+    {}
+    /// \brief Convenience function to queue a request to get a command
+    ///     message.
+    ModuleCCSession::AsyncRecvRequestID
+        registerCommand(const string& recipient)
+    {
+        return (mccs_.groupRecvMsgAsync(
+            bind(&AsyncReceiveCCSessionTest::callback, this, next_flag_ ++, _1,
+                 _2, _3), false, -1, recipient));
+    }
+    /// \brief Convenience function to queue a request to get a reply
+    ///     message.
+    ModuleCCSession::AsyncRecvRequestID
+        registerReply(int seq)
+    {
+        return (mccs_.groupRecvMsgAsync(
+            bind(&AsyncReceiveCCSessionTest::callback, this, next_flag_ ++, _1,
+                 _2, _3), false, seq));
+    }
+    /// \brief Check the next called callback was with this flag
+    void called(int flag) {
+        ASSERT_FALSE(called_.empty());
+        EXPECT_EQ(flag, *called_.begin());
+        called_.pop_front();
+    }
+    /// \brief Checks that no more callbacks were called.
+    void nothingCalled() {
+        EXPECT_TRUE(called_.empty());
+    }
+    /// \brief The testet session.
+    ModuleCCSession mccs_;
+    /// \brief The value of message on the last called callback.
+    ConstElementPtr last_msg_;
+private:
+    /// \brief The next flag to be handed out
+    int next_flag_;
+    /// \brief Flags of callbacks already called (as FIFO)
+    list<int> called_;
+    /// \brief This is the callback registered to the tested groupRecvMsgAsync
+    ///     function.
+    void callback(int store_flag, const ConstElementPtr&,
+                  const ConstElementPtr& msg,
+                  const ModuleCCSession::AsyncRecvRequestID&)
+    {
+        called_.push_back(store_flag);
+        last_msg_ = msg;
+    }
+};
+
+// Test we can receive a command, without anything fancy yet
+TEST_F(AsyncReceiveCCSessionTest, simpleCommand) {
+    // Push the message inside
+    ConstElementPtr msg(el("{}"));
+    session.addMessage(msg, "test group", "<unused>");
+    EXPECT_TRUE(mccs_.hasQueuedMsgs());
+    // Register the callback
+    registerCommand("test group");
+    // But the callback should not be called yet
+    // (even if the message is there).
+    nothingCalled();
+    // But when we call the checkCommand(), it should be called.
+    mccs_.checkCommand();
+    called(0);
+    EXPECT_EQ(msg, last_msg_);
+    // But only once
+    nothingCalled();
+    // And the message should be eaten
+    EXPECT_FALSE(mccs_.hasQueuedMsgs());
+    // The callback should have been eaten as well, inserting another
+    // message will not invoke it again
+    session.addMessage(msg, "test group", "<unused>");
+    mccs_.checkCommand();
+    nothingCalled();
+}
+
+// Very similar to simpleCommand, but with a response message
+TEST_F(AsyncReceiveCCSessionTest, simpleResponse) {
+    // Push the message inside
+    ConstElementPtr msg(el("{}"));
+    session.addMessage(msg, "<ignored>", "<unused>", 1);
+    EXPECT_TRUE(mccs_.hasQueuedMsgs());
+    // Register the callback
+    registerReply(1);
+    // But the callback should not be called yet
+    // (even if the message is there).
+    nothingCalled();
+    // But when we call the checkCommand(), it should be called.
+    mccs_.checkCommand();
+    called(0);
+    EXPECT_EQ(msg, last_msg_);
+    // But only once
+    nothingCalled();
+    // And the message should be eaten
+    EXPECT_FALSE(mccs_.hasQueuedMsgs());
+    // The callback should have been eaten as well, inserting another
+    // message will not invoke it again
+    session.addMessage(msg, "test group", "<unused>");
+    mccs_.checkCommand();
+    nothingCalled();
+}
+
 void doRelatedLoggersTest(const char* input, const char* expected) {
     ConstElementPtr all_conf = isc::data::Element::fromJSON(input);
     ConstElementPtr expected_conf = isc::data::Element::fromJSON(expected);

+ 2 - 1
src/lib/config/tests/fake_session.cc

@@ -228,12 +228,13 @@ FakeSession::getFirstMessage(std::string& group, std::string& to) const {
 
 void
 FakeSession::addMessage(ConstElementPtr msg, const std::string& group,
-                        const std::string& to)
+                        const std::string& to, int seq)
 {
     ElementPtr m_el = Element::createList();
     m_el->add(Element::create(group));
     m_el->add(Element::create(to));
     m_el->add(msg);
+    m_el->add(Element::create(seq));
     if (!msg_queue_) {
         msg_queue_ = Element::createList();
     }

+ 1 - 1
src/lib/config/tests/fake_session.h

@@ -74,7 +74,7 @@ public:
     isc::data::ConstElementPtr getFirstMessage(std::string& group,
                                                std::string& to) const;
     void addMessage(isc::data::ConstElementPtr, const std::string& group,
-                    const std::string& to);
+                    const std::string& to, int seq = -1);
     bool haveSubscription(const std::string& group,
                           const std::string& instance);
     bool haveSubscription(const isc::data::ConstElementPtr group,