/// @brief Thrown if the request queue is full when an enqueue is attempted.
-class D2QueueMgrQueFull : public isc::Exception {
+class D2QueueMgrQueueFull : public isc::Exception {
public:
- D2QueueMgrQueFull(const char* file, size_t line, const char* what) :
+ D2QueueMgrQueueFull(const char* file, size_t line, const char* what) :
isc::Exception(file, line, what) { };
};
/// @brief Thrown if the request queue empty and a read is attempted.
-class D2QueueMgrQueEmpty : public isc::Exception {
+class D2QueueMgrQueueEmpty : public isc::Exception {
public:
- D2QueueMgrQueEmpty(const char* file, size_t line, const char* what) :
+ D2QueueMgrQueueEmpty(const char* file, size_t line, const char* what) :
isc::Exception(file, line, what) { };
};
+/// @brief Thrown if a queue index is beyond the end of the queue
+class D2QueueMgrInvalidIndex : public isc::Exception {
+public:
+ D2QueueMgrInvalidIndex(const char* file, size_t line, const char* what) :
+ isc::Exception(file, line, what) { };
+};
+
+
/// @brief D2QueueMgr creates and manages a queue of DNS update requests.
///
/// D2QueueMgr is class specifically designed as an integral part of DHCP-DDNS.
///
/// @param stop_state is one of the three stopped state values.
///
- /// @throw Throws D2QueueMgrError if stop_state is a valid stop state.
+ /// @throw D2QueueMgrError if stop_state is a valid stop state.
void stopListening(const State stop_state = STOPPED);
/// @brief Deletes the current listener
///
/// @param max_queue_size is the new maximum size of the queue.
///
- /// @throw Throws D2QueueMgrError if the new value is less than one or if
+ /// @throw D2QueueMgrError if the new value is less than one or if
/// the new value is less than the number of entries currently in the
/// queue.
void setMaxQueueSize(const size_t max_queue_size);
/// approach to task selection. Note, the entry is not removed from the
/// queue.
///
- /// @throw Throws D2QueueMgrQueEmpty if there are no entries in the queue.
+ /// @return Pointer reference to the queue entry.
+ ///
+ /// @throw D2QueueMgrQueEmpty if there are no entries in the queue.
const dhcp_ddns::NameChangeRequestPtr& peek() const;
+ /// @brief Returns the entry at a given position in the queue.
+ ///
+ /// Note that the entry is not removed from the queue.
+ /// @param index the index of the entry in the queue to fetch.
+ /// Valid values are 0 (front of the queue) to (queue size - 1).
+ ///
+ /// @return Pointer reference to the queue entry.
+ ///
+ /// @throw D2QueueMgrInvalidIndex if the given index is beyond the
+ /// end of the queue.
+ const dhcp_ddns::NameChangeRequestPtr& peekAt(size_t index) const;
+
+ /// @brief Removes the entry at a given position in the queue.
+ ///
+ /// @param index the index of the entry in the queue to remove.
+ /// Valid values are 0 (front of the queue) to (queue size - 1).
+ ///
+ /// @throw D2QueueMgrInvalidIndex if the given index is beyond the
+ /// end of the queue.
+ void dequeueAt(size_t index);
+
/// @brief Removes the entry at the front of the queue.
///
- /// @throw Throws D2QueueMgrQueEmpty if there are no entries in the queue.
+ /// @throw D2QueueMgrQueEmpty if there are no entries in the queue.
void dequeue();
/// @brief Adds a request to the end of the queue.
TEST(D2QueueMgrBasicTest, constructionTests) {
isc::asiolink::IOService io_service;
- // Verify that constructing with max queue size of zero is not allowed.
+ // Verify that constructing with max queue size of zero is not allowed.
EXPECT_THROW(D2QueueMgr(io_service, 0), D2QueueMgrError);
// Verify that valid constructor works.
/// 1. Following construction queue is empty
/// 2. Attempting to peek at an empty queue is not allowed
/// 3. Attempting to dequeue an empty queue is not allowed
-/// 4. Peek returns the first entry on the queue without altering queue content
+/// 4. Peek returns the first entry on the queue without altering queue content
/// 5. Dequeue removes the first entry on the queue
TEST(D2QueueMgrBasicTest, basicQueueTests) {
isc::asiolink::IOService io_service;
EXPECT_EQ(0, queue_mgr->getQueueSize());
// Verify that peek and dequeue both throw when queue is empty.
- EXPECT_THROW(queue_mgr->peek(), D2QueueMgrQueEmpty);
- EXPECT_THROW(queue_mgr->dequeue(), D2QueueMgrQueEmpty);
+ EXPECT_THROW(queue_mgr->peek(), D2QueueMgrQueueEmpty);
+ EXPECT_THROW(queue_mgr->dequeue(), D2QueueMgrQueueEmpty);
// Vector to keep track of the NCRs we que.
std::vector<NameChangeRequestPtr>ref_msgs;
- NameChangeRequestPtr ncr;
+ NameChangeRequestPtr ncr;
// Iterate over the list of requests and add each to the queue.
for (int i = 0; i < VALID_MSG_CNT; i++) {
// Create the ncr and add to our reference list.
- ASSERT_NO_THROW(ncr = NameChangeRequest::fromJSON(valid_msgs[i]));
+ ASSERT_NO_THROW(ncr = NameChangeRequest::fromJSON(valid_msgs[i]));
ref_msgs.push_back(ncr);
-
+
// Verify that the request can be added to the queue and queue
// size increments accordingly.
EXPECT_NO_THROW(queue_mgr->enqueue(ncr));
}
// Loop through and verify that the queue contents match the
- // reference list.
+ // reference list.
for (int i = 0; i < VALID_MSG_CNT; i++) {
// Verify that peek on a non-empty queue returns first entry
// without altering queue content.
// Verify the dequeueing from non-empty queue works
EXPECT_NO_THROW(queue_mgr->dequeue());
-
- // Verify queue size decrements following dequeue.
+
+ // Verify queue size decrements following dequeue.
EXPECT_EQ(VALID_MSG_CNT-(i+1), queue_mgr->getQueueSize());
}
+
+ // Iterate over the list of requests and add each to the queue.
+ for (int i = 0; i < VALID_MSG_CNT; i++) {
+ // Create the ncr and add to our reference list.
+ ASSERT_NO_THROW(ncr = NameChangeRequest::fromJSON(valid_msgs[i]));
+ ref_msgs.push_back(ncr);
+ EXPECT_NO_THROW(queue_mgr->enqueue(ncr));
+ }
+
+ // Verify queue count is correct.
+ EXPECT_EQ(VALID_MSG_CNT, queue_mgr->getQueueSize());
+
+ // Verfiy that peekAt returns the correct entry.
+ EXPECT_NO_THROW(ncr = queue_mgr->peekAt(1));
+ EXPECT_TRUE (*(ref_msgs[1]) == *ncr);
+
+ // Verfiy that dequeueAt removes the correct entry.
+ // Removing it, this should shift the queued entries forward by one.
+ EXPECT_NO_THROW(queue_mgr->dequeueAt(1));
+ EXPECT_NO_THROW(ncr = queue_mgr->peekAt(1));
+ EXPECT_TRUE (*(ref_msgs[2]) == *ncr);
+
+ // Verify the peekAt and dequeueAt throw when given indexes beyond the end.
+ EXPECT_THROW(queue_mgr->peekAt(VALID_MSG_CNT + 1), D2QueueMgrInvalidIndex);
+ EXPECT_THROW(queue_mgr->dequeueAt(VALID_MSG_CNT + 1),
+ D2QueueMgrInvalidIndex);
}
/// @brief Compares two NameChangeRequests for equality.
isc::asiolink::IntervalTimer test_timer_;
D2QueueMgrPtr queue_mgr_;
- NameChangeSender::Result send_result_;
+ NameChangeSender::Result send_result_;
std::vector<NameChangeRequestPtr> sent_ncrs_;
std::vector<NameChangeRequestPtr> received_ncrs_;
QueueMgrUDPTest() : io_service_(), test_timer_(io_service_) {
isc::asiolink::IOAddress addr(TEST_ADDRESS);
// Create our sender instance. Note that reuse_address is true.
- sender_.reset(new NameChangeUDPSender(addr, SENDER_PORT,
+ sender_.reset(new NameChangeUDPSender(addr, SENDER_PORT,
addr, LISTENER_PORT,
FMT_JSON, *this, 100, true));
};
/// @brief Tests D2QueueMgr's state model.
-/// This test verifies that:
+/// This test verifies that:
/// 1. Upon construction, initial state is NOT_INITTED.
/// 2. Cannot start listening from while state is NOT_INITTED.
/// 3. Successful listener initialization transitions from NOT_INITTED
-/// to INITTED.
+/// to INITTED.
/// 4. Attempting to initialize the listener from INITTED state is not
/// allowed.
/// 5. Starting listener from INITTED transitions to RUNNING.
/// 7. Starting listener from STOPPED transitions to RUNNING.
TEST_F (QueueMgrUDPTest, stateModelTest) {
// Create the queue manager.
- EXPECT_NO_THROW(queue_mgr_.reset(new D2QueueMgr(io_service_,
+ EXPECT_NO_THROW(queue_mgr_.reset(new D2QueueMgr(io_service_,
VALID_MSG_CNT)));
// Verify that the initial state is NOT_INITTED.
// Verify that attempting to initialize the listener, from INITTED
// is not allowed.
EXPECT_THROW(queue_mgr_->initUDPListener(addr, LISTENER_PORT,
- FMT_JSON, true),
+ FMT_JSON, true),
D2QueueMgrError);
-
+
// Verify that we can enter the RUNNING from INITTED by starting the
// listener.
EXPECT_NO_THROW(queue_mgr_->startListening());
EXPECT_EQ(D2QueueMgr::NOT_INITTED, queue_mgr_->getMgrState());
}
-/// @brief Tests D2QueueMgr's ability to manage received requests
-/// This test verifies that:
+/// @brief Tests D2QueueMgr's ability to manage received requests
+/// This test verifies that:
/// 1. Requests can be received, queued, and dequeued
/// 2. Once the queue is full, a subsequent request transitions
/// manager to STOPPED_QUEUE_FULL state.
NameChangeRequestPtr received_ncr;
// Create the queue manager and start listening..
- ASSERT_NO_THROW(queue_mgr_.reset(new D2QueueMgr(io_service_,
+ ASSERT_NO_THROW(queue_mgr_.reset(new D2QueueMgr(io_service_,
VALID_MSG_CNT)));
ASSERT_EQ(D2QueueMgr::NOT_INITTED, queue_mgr_->getMgrState());
// each one. Verify and dequeue as they arrive.
for (int i = 0; i < VALID_MSG_CNT; i++) {
// Create the ncr and add to our reference list.
- ASSERT_NO_THROW(send_ncr = NameChangeRequest::fromJSON(valid_msgs[i]));
+ ASSERT_NO_THROW(send_ncr = NameChangeRequest::fromJSON(valid_msgs[i]));
ASSERT_NO_THROW(sender_->sendRequest(send_ncr));
// running two should do the send then the receive
// each one. Allow them to accumulate in the queue.
for (int i = 0; i < VALID_MSG_CNT; i++) {
// Create the ncr and add to our reference list.
- ASSERT_NO_THROW(send_ncr = NameChangeRequest::fromJSON(valid_msgs[i]));
+ ASSERT_NO_THROW(send_ncr = NameChangeRequest::fromJSON(valid_msgs[i]));
ASSERT_NO_THROW(sender_->sendRequest(send_ncr));
// running two should do the send then the receive
EXPECT_NO_THROW(io_service_.run_one());
EXPECT_EQ(D2QueueMgr::STOPPED_QUEUE_FULL, queue_mgr_->getMgrState());
- // Verify queue size did not increase beyond max.
+ // Verify queue size did not increase beyond max.
EXPECT_EQ(VALID_MSG_CNT, queue_mgr_->getQueueSize());
// Verify that setting max queue size to a value less than current size of
- // the queue is not allowed.
+ // the queue is not allowed.
EXPECT_THROW(queue_mgr_->setMaxQueueSize(VALID_MSG_CNT-1), D2QueueMgrError);
EXPECT_EQ(VALID_MSG_CNT, queue_mgr_->getQueueSize());