BIND 10 master, updated. 0e0d28e6bf3276aaf59c1c9da97e1bee538eae09 Merge #1914
BIND 10 source code commits
bind10-changes at lists.isc.org
Mon May 21 12:11:29 UTC 2012
The branch, master has been updated
via 0e0d28e6bf3276aaf59c1c9da97e1bee538eae09 (commit)
via 9915ecdc183e64e22ba51f233d1667ad3091972a (commit)
via 410df5ee446d69d53ca45e21307d07c54b5b2b76 (commit)
via b3c7d1eaf3835c8bc13a7cc136b85e79aaf16934 (commit)
via 51f3a86709293442f3bb04f775ae42d7d24b03dd (commit)
via 12c0fa4fd0676ab17616d34a522d526f8139586a (commit)
via 609581d6dd36f50ad9118b2869756c2f26c5afd4 (commit)
via d74f9a69b7a7c2f80adc61be1e4a38338d24558f (commit)
via 1455f670ced8213e01848e24e3a2d994ed16b74d (commit)
via 6d4b2e6b54ae93bcd438e253573b62c11535b436 (commit)
via a2be2f5cfe81a85df13a0ea977af6a9bddf3040b (commit)
via 4aea6b74d6a48ee9e3666745ed7da416b31c2728 (commit)
via d06b9b84af34e84cadab87920fc1742f8b029d7c (commit)
via 132d530f80654677dfc10e9a0f88edd272666385 (commit)
via b174ac98fbe2c9bae96edd0faf2e8884cbbac4fd (commit)
via 4bdecaadf9b845af3c2b2b11213539a4a0226284 (commit)
via a43b1b6641de54cc27e7abbf40f0a49c2d9d617a (commit)
via 51b0205f48ad15ae28eafaa63890d3a671acc595 (commit)
via 480d50eef89a78c5ed326fa392254aeb2ec6df06 (commit)
from 42d8e0ec9a379888f3013a3458ea6f97d38d5332 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit 0e0d28e6bf3276aaf59c1c9da97e1bee538eae09
Merge: 42d8e0ec9a379888f3013a3458ea6f97d38d5332 9915ecdc183e64e22ba51f233d1667ad3091972a
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Mon May 21 13:56:57 2012 +0200
Merge #1914
This is the asynchronous read on ModuleCCSession.
-----------------------------------------------------------------------
Summary of changes:
src/lib/config/ccsession.cc | 95 +++++++
src/lib/config/ccsession.h | 132 +++++++++-
src/lib/config/tests/ccsession_unittests.cc | 283 +++++++++++++++++++-
src/lib/config/tests/fake_session.cc | 8 +-
src/lib/config/tests/fake_session.h | 2 +-
.../server_common/tests/socket_requestor_test.cc | 2 +
6 files changed, 513 insertions(+), 9 deletions(-)
-----------------------------------------------------------------------
diff --git a/src/lib/config/ccsession.cc b/src/lib/config/ccsession.cc
index 63fa4cd..d4c6653 100644
--- a/src/lib/config/ccsession.cc
+++ b/src/lib/config/ccsession.cc
@@ -601,6 +601,11 @@ ModuleCCSession::checkCommand() {
ConstElementPtr cmd, routing, data;
if (session_.group_recvmsg(routing, data, true)) {
+ // In case the message is wanted asynchronously, it gets used.
+ if (checkAsyncRecv(routing, data)) {
+ return (0);
+ }
+
/* ignore result messages (in case we're out of sync, to prevent
* pingpongs */
if (data->getType() != Element::map || data->contains("result")) {
@@ -764,5 +769,95 @@ ModuleCCSession::sendStopping() {
session_.group_sendmsg(cmd, "ConfigManager");
}
+class ModuleCCSession::AsyncRecvRequest {
+public: // Everything is public here, as the definition is hidden anyway
+ AsyncRecvRequest(const AsyncRecvCallback& cb, const string& rcp, int sq,
+ bool reply) :
+ callback(cb),
+ recipient(rcp),
+ seq(sq),
+ is_reply(reply)
+ {}
+ const AsyncRecvCallback callback;
+ const string recipient;
+ const int seq;
+ const bool is_reply;
+};
+
+ModuleCCSession::AsyncRecvRequestID
+ModuleCCSession::groupRecvMsgAsync(const AsyncRecvCallback& callback,
+ bool is_reply, int seq,
+ const string& recipient) {
+ // This just stores the request, the handling is done in checkCommand()
+
+ // push_back would be simpler, but it does not return the iterator we need
+ return (async_recv_requests_.insert(async_recv_requests_.end(),
+ AsyncRecvRequest(callback, recipient,
+ seq, is_reply)));
+}
+
+bool
+ModuleCCSession::checkAsyncRecv(const ConstElementPtr& envelope,
+ const ConstElementPtr& msg)
+{
+ for (AsyncRecvRequestID request(async_recv_requests_.begin());
+ request != async_recv_requests_.end(); ++request) {
+ // Just go through all the requests and look for a matching one
+ if (requestMatch(*request, envelope)) {
+ // We want the request to be still alive at the time we
+ // call the callback. But we need to remove it on an exception
+ // too, so we use the class. If just C++ had the finally keyword.
+ class RequestDeleter {
+ public:
+ RequestDeleter(AsyncRecvRequests& requests,
+ AsyncRecvRequestID& request) :
+ requests_(requests),
+ request_(request)
+ { }
+ ~RequestDeleter() {
+ requests_.erase(request_);
+ }
+ private:
+ AsyncRecvRequests& requests_;
+ AsyncRecvRequestID& request_;
+ };
+ RequestDeleter deleter(async_recv_requests_, request);
+ // Call the callback
+ request->callback(envelope, msg, request);
+ return (true);
+ }
+ }
+ return (false);
+}
+
+bool
+ModuleCCSession::requestMatch(const AsyncRecvRequest& request,
+ const ConstElementPtr& envelope) const
+{
+ if (request.is_reply != envelope->contains("reply")) {
+ // Wrong type of message
+ return (false);
+ }
+ if (request.is_reply &&
+ (request.seq == -1 ||
+ request.seq == envelope->get("reply")->intValue())) {
+ // This is the correct reply
+ return (true);
+ }
+ if (!request.is_reply &&
+ (request.recipient.empty() ||
+ request.recipient == envelope->get("group")->stringValue())) {
+ // This is the correct command
+ return (true);
+ }
+ // If nothing from the above, we don't want it
+ return (false);
+}
+
+void
+ModuleCCSession::cancelAsyncRecv(const AsyncRecvRequestID& id) {
+ async_recv_requests_.erase(id);
+}
+
}
}
diff --git a/src/lib/config/ccsession.h b/src/lib/config/ccsession.h
index 059968c..e96a33d 100644
--- a/src/lib/config/ccsession.h
+++ b/src/lib/config/ccsession.h
@@ -15,13 +15,16 @@
#ifndef __CCSESSION_H
#define __CCSESSION_H 1
-#include <string>
-
#include <config/config_data.h>
#include <config/module_spec.h>
+
#include <cc/session.h>
#include <cc/data.h>
+#include <string>
+#include <list>
+#include <boost/function.hpp>
+
namespace isc {
namespace config {
@@ -358,15 +361,140 @@ public:
return (session_.group_recvmsg(envelope, msg, nonblock, seq));
};
+ /// \brief Forward declaration of internal data structure.
+ ///
+ /// This holds information about one asynchronous request to receive
+ /// a message. It is declared as public to allow declaring other derived
+ /// types, but without showing the internal representation.
+ class AsyncRecvRequest;
+
+ /// \brief List of all requests for asynchronous reads.
+ typedef std::list<AsyncRecvRequest> AsyncRecvRequests;
+
+ /// \brief Identifier of single request for asynchronous read.
+ typedef AsyncRecvRequests::iterator AsyncRecvRequestID;
+
+ /// \brief Callback which is called when an asynchronous receive finishes.
+ ///
+ /// This is the callback used by groupRecvMsgAsync() function. It is called
+ /// when a matching message arrives. It receives following parameters when
+ /// called:
+ /// - The envelope of the message
+ /// - The message itself
+ /// - The ID of the request, as returned by corresponding groupRecvMsgAsync
+ /// call.
+ ///
+ /// It is possible to throw exceptions from the callback, but they will not
+ /// be caught and they will get propagated out through the checkCommand()
+ /// call. This, if not handled on higher level, will likely terminate the
+ /// application. However, the ModuleCCSession internals will be in
+ /// well-defined state after the call (both the callback and the message
+ /// will be removed from the queues as already called).
+ typedef boost::function3<void, const isc::data::ConstElementPtr&,
+ const isc::data::ConstElementPtr&,
+ const AsyncRecvRequestID&>
+ AsyncRecvCallback;
+
+ /// \brief Receive a message from the CC session asynchronously.
+ ///
+ /// This registers a callback which is called when a matching message
+ /// is received. This message returns immediately.
+ ///
+ /// Once a matching message arrives, the callback is called with the
+ /// envelope of the message, the message itself and the result of this
+ /// function call (which might be useful for identifying which of many
+ /// events the recipient is waiting for this is). This makes the callback
+ /// used and is not called again even if a message that would match
+ /// arrives later (this is a single-shot callback).
+ ///
+ /// The callback is never called from within this function. Even if there
+ /// are queued messages, the callback would be called once checkCommand()
+ /// is invoked (possibly from start() or the constructor).
+ ///
+ /// The matching is as follows. If is_reply is true, only replies are
+ /// considered. In that case, if seq is -1, any reply is accepted. If
+ /// it is something else than -1, only the reply with matching seq is
+ /// taken. This may be used to receive replies to commands
+ /// asynchronously.
+ ///
+ /// 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 (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
+ /// parameters, it steals the message and no callback matching it as well
+ /// is called. Then, all the queued asynchronous receives are considered,
+ /// with the oldest active ones taking precedence (they work as FIFO).
+ /// If none of them matches, generic command and config handling takes
+ /// place. If it is not handled by that, the message is dropped. However,
+ /// it is better if there's just one place that wants to receive each given
+ /// message.
+ ///
+ /// \exception std::bad_alloc if there isn't enough memory to store the
+ /// callback.
+ /// \param callback is the function to be called when a matching message
+ /// arrives.
+ /// \param is_reply specifies if the desired message should be a reply or
+ /// a command.
+ /// \param seq specifies the reply sequence number in case a reply is
+ /// desired. The default -1 means any reply is OK.
+ /// \param recipient is the CC channel to which the command should be
+ /// addressed to match (in case is_reply is false). Empty means any
+ /// 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, int seq = -1,
+ const std::string& recipient =
+ std::string());
+
+ /// \brief Removes yet unused request for asynchronous receive.
+ ///
+ /// This function cancels a request previously queued by
+ /// groupRecvMsgAsync(). You may use it only before the callback was
+ /// already triggered. If you call it with an ID of callback that
+ /// already happened or was already canceled, the behaviour is undefined
+ /// (but something like a crash is very likely, as the function removes
+ /// an item from a list and this would be removing it from a list that
+ /// does not contain the item).
+ ///
+ /// It is important to cancel requests that are no longer going to happen
+ /// for some reason, as the request would occupy memory forever.
+ ///
+ /// \param id The id of request as returned by groupRecvMsgAsync.
+ void cancelAsyncRecv(const AsyncRecvRequestID& id);
+
private:
ModuleSpec readModuleSpecification(const std::string& filename);
void startCheck();
void sendStopping();
+ /// \brief Check if the message is wanted by asynchronous read
+ ///
+ /// It checks if any of the previously queued requests match
+ /// the message. If so, the callback is dispatched and removed.
+ ///
+ /// \param envelope The envelope of the message.
+ /// \param msg The actual message data.
+ /// \return True if the message was used for a callback, false
+ /// otherwise.
+ bool checkAsyncRecv(const data::ConstElementPtr& envelope,
+ const data::ConstElementPtr& msg);
+ /// \brief Checks if a message with this envelope matches the request
+ bool requestMatch(const AsyncRecvRequest& request,
+ const data::ConstElementPtr& envelope) const;
bool started_;
std::string module_name_;
isc::cc::AbstractSession& session_;
ModuleSpec module_specification_;
+ AsyncRecvRequests async_recv_requests_;
isc::data::ConstElementPtr handleConfigUpdate(
isc::data::ConstElementPtr new_config);
diff --git a/src/lib/config/tests/ccsession_unittests.cc b/src/lib/config/tests/ccsession_unittests.cc
index abaff8e..3fca741 100644
--- a/src/lib/config/tests/ccsession_unittests.cc
+++ b/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,13 +711,286 @@ TEST_F(CCSessionTest, doubleStartWithAddRemoteConfig) {
FakeSession::DoubleRead);
}
-namespace {
+/// \brief Test fixture for asynchronous receiving of messages.
+///
+/// This is an 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),
+ msg_(el("{\"result\": [0]}")),
+ next_flag_(0)
+ {
+ // This is just to make sure the messages get through the fake
+ // session.
+ session.subscribe("test group");
+ session.subscribe("other group");
+ session.subscribe("<ignored>");
+ // Get rid of all unrelated stray messages
+ while (session.getMsgQueue()->size() > 0) {
+ session.getMsgQueue()->remove(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), true, 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 tested session.
+ ModuleCCSession mccs_;
+ /// \brief The value of message on the last called callback.
+ ConstElementPtr last_msg_;
+ /// \brief A message that can be used
+ ConstElementPtr msg_;
+ // Shared part of the simpleCommand and similar tests.
+ void commandTest(const string& group) {
+ // Push the message inside
+ session.addMessage(msg_, "test group", "<unused>");
+ EXPECT_TRUE(mccs_.hasQueuedMsgs());
+ // Register the callback
+ registerCommand(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();
+ }
+ /// \brief Shared part of the simpleResponse and wildcardResponse tests.
+ void responseTest(int seq) {
+ // Push the message inside
+ session.addMessage(msg_, "<ignored>", "<unused>", 1);
+ EXPECT_TRUE(mccs_.hasQueuedMsgs());
+ // Register the callback
+ registerReply(seq);
+ // 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();
+ }
+ /// \brief Shared part of the noMatch* tests
+ void noMatchTest(int seq, int wanted_seq, bool is_reply) {
+ // Push the message inside
+ session.addMessage(msg_, "other group", "<unused>", seq);
+ EXPECT_TRUE(mccs_.hasQueuedMsgs());
+ // Register the callback
+ if (is_reply) {
+ registerReply(wanted_seq);
+ } else {
+ registerCommand("test group");
+ }
+ // But the callback should not be called yet
+ // (even if the message is there).
+ nothingCalled();
+ // And even not now, because it does not match.
+ mccs_.checkCommand();
+ nothingCalled();
+ // And the message should be eaten by the checkCommand
+ EXPECT_FALSE(mccs_.hasQueuedMsgs());
+ }
+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) {
+ commandTest("test group");
+}
+
+// Test we can receive a "wildcard" command - without specifying the
+// group to subscribe to. Very similar to simpleCommand test.
+TEST_F(AsyncReceiveCCSessionTest, wildcardCommand) {
+ commandTest("");
+}
+
+// Very similar to simpleCommand, but with a response message
+TEST_F(AsyncReceiveCCSessionTest, simpleResponse) {
+ responseTest(1);
+}
+
+// Matching a response message with wildcard
+TEST_F(AsyncReceiveCCSessionTest, wildcardResponse) {
+ responseTest(-1);
+}
+
+// Check that a wrong command message is not matched
+TEST_F(AsyncReceiveCCSessionTest, noMatchCommand) {
+ noMatchTest(-1, -1, false);
+}
+
+// Check that a wrong response message is not matched
+TEST_F(AsyncReceiveCCSessionTest, noMatchResponse) {
+ noMatchTest(2, 3, true);
+}
+
+// Check that a command will not match on a reply check and vice versa
+TEST_F(AsyncReceiveCCSessionTest, noMatchResponseAgainstCommand) {
+ // Send a command and check it is not matched as a response
+ noMatchTest(-1, -1, true);
+}
+
+TEST_F(AsyncReceiveCCSessionTest, noMatchCommandAgainstResponse) {
+ noMatchTest(2, -1, false);
+}
+
+// We check for command several times before the message actually arrives.
+TEST_F(AsyncReceiveCCSessionTest, delayedCallback) {
+ // First, register the callback
+ registerReply(1);
+ // And see it is not called, because the message is not there yet
+ EXPECT_FALSE(mccs_.hasQueuedMsgs());
+ for (size_t i(0); i < 100; ++ i) {
+ mccs_.checkCommand();
+ EXPECT_FALSE(mccs_.hasQueuedMsgs());
+ nothingCalled();
+ }
+ // Now the message finally arrives
+ session.addMessage(msg_, "<ignored>", "<unused>", 1);
+ EXPECT_TRUE(mccs_.hasQueuedMsgs());
+ // And now, the callback is happily triggered.
+ mccs_.checkCommand();
+ called(0);
+ EXPECT_EQ(msg_, last_msg_);
+ // But only once
+ nothingCalled();
+}
+
+// See that if we put multiple messages inside, and request some callbacks,
+// the callbacks are called in the order of messages, not in the order they
+// were registered.
+TEST_F(AsyncReceiveCCSessionTest, outOfOrder) {
+ // First, put some messages there
+ session.addMessage(msg_, "<ignored>", "<unused>", 1);
+ session.addMessage(msg_, "test group", "<unused>");
+ session.addMessage(msg_, "other group", "<unused>");
+ session.addMessage(msg_, "<ignored>", "<unused>", 2);
+ session.addMessage(msg_, "<ignored>", "<unused>", 3);
+ session.addMessage(msg_, "<ignored>", "<unused>", 4);
+ // Now register some callbacks
+ registerReply(13); // Will not be called
+ registerCommand("other group"); // Matches 3rd message
+ registerReply(2); // Matches 4th message
+ registerCommand(""); // Matches the 2nd message
+ registerCommand("test group"); // Will not be called
+ registerReply(-1); // Matches the 1st message
+ registerReply(-1); // Matches the 5th message
+ // Process all messages there
+ while (mccs_.hasQueuedMsgs()) {
+ mccs_.checkCommand();
+ }
+ // These are the numbers of callbacks in the order of messages
+ called(5);
+ called(3);
+ called(1);
+ called(2);
+ called(6);
+ // The last message doesn't trigger anything, so nothing more is called
+ nothingCalled();
+}
+
+// We first add, then remove the callback again and check that nothing is
+// matched.
+TEST_F(AsyncReceiveCCSessionTest, cancel) {
+ // Add the callback
+ ModuleCCSession::AsyncRecvRequestID request(registerReply(1));
+ // Add corresponding message
+ session.addMessage(msg_, "<ignored>", "<unused>", 1);
+ EXPECT_TRUE(mccs_.hasQueuedMsgs());
+ // And now, remove the callback again
+ mccs_.cancelAsyncRecv(request);
+ // And see that Nothing Happens(TM)
+ mccs_.checkCommand();
+ EXPECT_FALSE(mccs_.hasQueuedMsgs());
+ nothingCalled();
+}
+
+// We add multiple requests and cancel only one of them to see the rest
+// is unaffected.
+TEST_F(AsyncReceiveCCSessionTest, cancelSome) {
+ // Register few callbacks
+ registerReply(1);
+ ModuleCCSession::AsyncRecvRequestID request(registerCommand(""));
+ registerCommand("test group");
+ // Put some messages there
+ session.addMessage(msg_, "test group", "<unused>");
+ session.addMessage(msg_, "<ignored>", "<unused>", 1);
+ // Cancel the second callback. Therefore the first message will be matched
+ // by the third callback, not by the second.
+ mccs_.cancelAsyncRecv(request);
+ // Now, process the messages
+ mccs_.checkCommand();
+ mccs_.checkCommand();
+ // And see how they matched
+ called(2);
+ called(0);
+ 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);
EXPECT_EQ(*expected_conf, *isc::config::getRelatedLoggers(all_conf));
}
-} // end anonymous namespace
TEST(LogConfigTest, relatedLoggersTest) {
// make sure logger configs for 'other' programs are ignored,
diff --git a/src/lib/config/tests/fake_session.cc b/src/lib/config/tests/fake_session.cc
index 177e629..157d4d6 100644
--- a/src/lib/config/tests/fake_session.cc
+++ b/src/lib/config/tests/fake_session.cc
@@ -139,6 +139,9 @@ FakeSession::recvmsg(ConstElementPtr& env, ConstElementPtr& msg, bool nonblock,
ElementPtr new_env = Element::createMap();
new_env->set("group", c_m->get(0));
new_env->set("to", c_m->get(1));
+ if (c_m->get(3)->intValue() != -1) {
+ new_env->set("reply", c_m->get(3));
+ }
env = new_env;
msg = c_m->get(2);
to_remove = c_m;
@@ -207,7 +210,7 @@ FakeSession::reply(ConstElementPtr envelope, ConstElementPtr newmsg) {
bool
FakeSession::hasQueuedMsgs() const {
- return (false);
+ return (msg_queue_ && msg_queue_->size() > 0);
}
ConstElementPtr
@@ -228,12 +231,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();
}
diff --git a/src/lib/config/tests/fake_session.h b/src/lib/config/tests/fake_session.h
index 79ff174..c91b519 100644
--- a/src/lib/config/tests/fake_session.h
+++ b/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,
diff --git a/src/lib/server_common/tests/socket_requestor_test.cc b/src/lib/server_common/tests/socket_requestor_test.cc
index 829b6d9..9adf84d 100644
--- a/src/lib/server_common/tests/socket_requestor_test.cc
+++ b/src/lib/server_common/tests/socket_requestor_test.cc
@@ -144,6 +144,7 @@ createExpectedRequest(const std::string& address,
packet->add(Element::create("Boss"));
packet->add(Element::create("*"));
packet->add(createCommand("get_socket", command_args));
+ packet->add(Element::create(-1));
return (packet);
}
@@ -284,6 +285,7 @@ createExpectedRelease(const std::string& token) {
packet->add(Element::create("Boss"));
packet->add(Element::create("*"));
packet->add(createCommand("drop_socket", command_args));
+ packet->add(Element::create(-1));
return (packet);
}
More information about the bind10-changes
mailing list