diff options
author | Thomas Markwalder <tmark@isc.org> | 2013-07-30 20:24:25 +0200 |
---|---|---|
committer | Thomas Markwalder <tmark@isc.org> | 2013-07-30 20:24:25 +0200 |
commit | f964dbc5497ea2aef884251c708007e97185df2e (patch) | |
tree | 904ea373e5727643e416ac7f0a843616d958b414 /src/bin | |
parent | [3052] Removed extraneous const function return type. (diff) | |
download | kea-f964dbc5497ea2aef884251c708007e97185df2e.tar.xz kea-f964dbc5497ea2aef884251c708007e97185df2e.zip |
[3052] Added peekAt and dequeueAt methods to D2QueueMgr.
In order to add some flexibility in manipulating queue contents
these two methods provide access to queue entries based on their
ordinal position.
Diffstat (limited to 'src/bin')
-rw-r--r-- | src/bin/d2/d2_queue_mgr.cc | 26 | ||||
-rw-r--r-- | src/bin/d2/d2_queue_mgr.h | 47 | ||||
-rw-r--r-- | src/bin/d2/tests/d2_queue_mgr_unittests.cc | 74 |
3 files changed, 113 insertions, 34 deletions
diff --git a/src/bin/d2/d2_queue_mgr.cc b/src/bin/d2/d2_queue_mgr.cc index aeb7ead691..9fe4ebb9e0 100644 --- a/src/bin/d2/d2_queue_mgr.cc +++ b/src/bin/d2/d2_queue_mgr.cc @@ -142,17 +142,39 @@ D2QueueMgr::removeListener() { const dhcp_ddns::NameChangeRequestPtr& D2QueueMgr::peek() const { if (getQueueSize() == 0) { - isc_throw(D2QueueMgrQueEmpty, + isc_throw(D2QueueMgrQueueEmpty, "D2QueueMgr peek attempted on an empty queue"); } return (ncr_queue_.front()); } +const dhcp_ddns::NameChangeRequestPtr& +D2QueueMgr::peekAt(size_t index) const { + if (index >= getQueueSize()) { + isc_throw(D2QueueMgrInvalidIndex, + "D2QueueMgr peek beyond end of queue attempted"); + } + + return (ncr_queue_.at(index)); +} + +void +D2QueueMgr::dequeueAt(size_t index) { + if (index >= getQueueSize()) { + isc_throw(D2QueueMgrInvalidIndex, + "D2QueueMgr dequeue beyond end of queue attempted"); + } + + RequestQueue::iterator pos = ncr_queue_.begin() + index; + ncr_queue_.erase(pos); +} + + void D2QueueMgr::dequeue() { if (getQueueSize() == 0) { - isc_throw(D2QueueMgrQueEmpty, + isc_throw(D2QueueMgrQueueEmpty, "D2QueueMgr dequeue attempted on an empty queue"); } diff --git a/src/bin/d2/d2_queue_mgr.h b/src/bin/d2/d2_queue_mgr.h index d47fc775b5..01b33ffbce 100644 --- a/src/bin/d2/d2_queue_mgr.h +++ b/src/bin/d2/d2_queue_mgr.h @@ -49,19 +49,27 @@ public: /// @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. @@ -216,7 +224,7 @@ public: /// /// @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 @@ -242,7 +250,7 @@ public: /// /// @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); @@ -258,12 +266,35 @@ public: /// 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. diff --git a/src/bin/d2/tests/d2_queue_mgr_unittests.cc b/src/bin/d2/tests/d2_queue_mgr_unittests.cc index 29062de05a..0fccf9b518 100644 --- a/src/bin/d2/tests/d2_queue_mgr_unittests.cc +++ b/src/bin/d2/tests/d2_queue_mgr_unittests.cc @@ -84,7 +84,7 @@ const long TEST_TIMEOUT = 5 * 1000; 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. @@ -104,7 +104,7 @@ TEST(D2QueueMgrBasicTest, constructionTests) { /// 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; @@ -119,19 +119,19 @@ TEST(D2QueueMgrBasicTest, basicQueueTests) { 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)); @@ -139,7 +139,7 @@ TEST(D2QueueMgrBasicTest, basicQueueTests) { } // 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. @@ -154,10 +154,36 @@ TEST(D2QueueMgrBasicTest, basicQueueTests) { // 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. @@ -178,14 +204,14 @@ public: 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)); @@ -218,11 +244,11 @@ public: }; /// @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. @@ -230,7 +256,7 @@ public: /// 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. @@ -248,9 +274,9 @@ TEST_F (QueueMgrUDPTest, stateModelTest) { // 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()); @@ -279,8 +305,8 @@ TEST_F (QueueMgrUDPTest, stateModelTest) { 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. @@ -295,7 +321,7 @@ TEST_F (QueueMgrUDPTest, liveFeedTest) { 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()); @@ -319,7 +345,7 @@ TEST_F (QueueMgrUDPTest, liveFeedTest) { // 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 @@ -343,7 +369,7 @@ TEST_F (QueueMgrUDPTest, liveFeedTest) { // 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 @@ -364,11 +390,11 @@ TEST_F (QueueMgrUDPTest, liveFeedTest) { 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()); |