namespace {
+class D2ClientMgrTestSendHandler : public D2ClientMgr {
+public:
+ /// @brief Constructor
+ D2ClientMgrTestSendHandler() : simulate_send_failure_(false), callback_count_(0) {
+ }
+
+ /// @brief Overrides base class completion callback.
+ ///
+ /// This method will be invoked each time a send completes. It allows
+ /// intervention prior to calling the production implementation in the
+ /// base. If simulate_send_failure_ is true, the base call impl will
+ /// be called with an error status, otherwise it will be called with
+ /// the result parameter given.
+ ///
+ /// @param result Result code of the send operation.
+ /// @param ncr NameChangeRequest which failed to send.
+ virtual void operator()(const dhcp_ddns::NameChangeSender::Result result,
+ dhcp_ddns::NameChangeRequestPtr& ncr) {
+ ++callback_count_;
+ if (simulate_send_failure_) {
+ simulate_send_failure_ = false;
+ D2ClientMgr::operator()(dhcp_ddns::NameChangeSender::ERROR, ncr);
+ } else {
+ D2ClientMgr::operator()(result, ncr);
+ }
+ }
+
+ /// @brief If true simulates a send which completed with a failed status.
+ bool simulate_send_failure_;
+
+ /// @brief Tracks the number times the completion handler is called.
+ int callback_count_;
+
+ /// Expose restricted members.
+ using D2ClientMgr::getSelectFd;
+};
+
/// @brief Test fixture for exercising D2ClientMgr send management
/// services. It inherits from D2ClientMgr to allow overriding various
/// methods and accessing otherwise restricted member. In particular it
/// overrides the NameChangeSender completion completion callback, allowing
/// the injection of send errors.
-class D2ClientMgrTest : public D2ClientMgr, public ::testing::Test {
+class D2ClientMgrTest : public ::testing::Test {
public:
- /// @brief If true simulates a send which completed with a failed status.
- bool simulate_send_failure_;
+ boost::shared_ptr<D2ClientMgrTestSendHandler> handle_;
+
/// @brief If true causes an exception throw in the client error handler.
bool error_handler_throw_;
- /// @brief Tracks the number times the completion handler is called.
- int callback_count_;
+
/// @brief Tracks the number of times the client error handler was called.
int error_handler_count_;
/// @brief Constructor
- D2ClientMgrTest() : simulate_send_failure_(false),
- error_handler_throw_(false),
- callback_count_(0), error_handler_count_(0) {
+ D2ClientMgrTest() : handle_(new D2ClientMgrTestSendHandler()),
+ error_handler_throw_(false),
+ error_handler_count_(0) {
}
/// @brief virtual Destructor
- virtual ~D2ClientMgrTest(){
+ virtual ~D2ClientMgrTest() {
+ handle_->stop();
+ handle_->stopSender();
}
/// @brief Updates the D2ClientMgr's configuration to DDNS enabled.
IOAddress sender_ip(server_ip.isV4() ? D2ClientConfig::DFT_V4_SENDER_IP :
D2ClientConfig::DFT_V6_SENDER_IP);
- ASSERT_NO_THROW(new_cfg.reset(new D2ClientConfig(true,
- server_ip, server_port,
- sender_ip, D2ClientConfig::DFT_SENDER_PORT,
- D2ClientConfig::DFT_MAX_QUEUE_SIZE,
- protocol, dhcp_ddns::FMT_JSON)));
+ ASSERT_NO_THROW(new_cfg.reset(new D2ClientConfig(true, server_ip, server_port,
+ sender_ip, D2ClientConfig::DFT_SENDER_PORT,
+ D2ClientConfig::DFT_MAX_QUEUE_SIZE,
+ protocol, dhcp_ddns::FMT_JSON)));
- ASSERT_NO_THROW(setD2ClientConfig(new_cfg));
- ASSERT_TRUE(ddnsEnabled());
+ ASSERT_NO_THROW(handle_->setD2ClientConfig(new_cfg));
+ ASSERT_TRUE(handle_->ddnsEnabled());
}
/// @brief Checks sender's select-fd against an expected state of readiness.
int select_fd = -1;
ASSERT_NO_THROW(
// cppcheck-suppress redundantAssignment
- select_fd = getSelectFd()
+ select_fd = handle_->getSelectFd()
);
FD_SET(select_fd, &read_fds);
}
}
- /// @brief Overrides base class completion callback.
- ///
- /// This method will be invoked each time a send completes. It allows
- /// intervention prior to calling the production implementation in the
- /// base. If simulate_send_failure_ is true, the base call impl will
- /// be called with an error status, otherwise it will be called with
- /// the result parameter given.
- ///
- /// @param result Result code of the send operation.
- /// @param ncr NameChangeRequest which failed to send.
- virtual void operator()(const dhcp_ddns::NameChangeSender::Result result,
- dhcp_ddns::NameChangeRequestPtr& ncr) {
- ++callback_count_;
- if (simulate_send_failure_) {
- simulate_send_failure_ = false;
- D2ClientMgr::operator()(dhcp_ddns::NameChangeSender::ERROR, ncr);
- } else {
- D2ClientMgr::operator()(result, ncr);
- }
- }
-
/// @brief Serves as the "application level" client error handler.
///
/// This method is passed into calls to startSender as the client error
return (dhcp_ddns::NameChangeRequest::fromJSON(ncr_str));
}
-
- /// Expose restricted members.
- using D2ClientMgr::getSelectFd;
};
-
/// @brief Checks that D2ClientMgr disable and enable a UDP sender.
TEST_F(D2ClientMgrTest, udpSenderEnableDisable) {
// Verify DDNS is disabled by default.
- ASSERT_FALSE(ddnsEnabled());
+ ASSERT_FALSE(handle_->ddnsEnabled());
// Verify we are not in send mode.
- ASSERT_FALSE(amSending());
+ ASSERT_FALSE(handle_->amSending());
// Enable DDNS with server at 127.0.0.1/prot 53001 via UDP.
enableDdns("127.0.0.1", 530001, dhcp_ddns::NCR_UDP);
- ASSERT_FALSE(amSending());
+ ASSERT_FALSE(handle_->amSending());
- ASSERT_NO_THROW(startSender(getErrorHandler()));
- ASSERT_TRUE(amSending());
+ ASSERT_NO_THROW(handle_->startSender(getErrorHandler()));
+ ASSERT_TRUE(handle_->amSending());
// Verify that we take sender out of send mode.
- ASSERT_NO_THROW(stopSender());
- ASSERT_FALSE(amSending());
+ ASSERT_NO_THROW(handle_->stopSender());
+ ASSERT_FALSE(handle_->amSending());
}
/// @brief Checks D2ClientMgr queuing methods with a UDP sender.
TEST_F(D2ClientMgrTest, udpSenderQueing) {
// Enable DDNS with server at 127.0.0.1/prot 53001 via UDP.
enableDdns("127.0.0.1", 530001, dhcp_ddns::NCR_UDP);
- ASSERT_FALSE(amSending());
+ ASSERT_FALSE(handle_->amSending());
// Queue should be empty.
- EXPECT_EQ(0, getQueueSize());
+ EXPECT_EQ(0, handle_->getQueueSize());
// Trying to peek past the end of the queue should throw.
- EXPECT_THROW(peekAt(1), dhcp_ddns::NcrSenderError);
+ EXPECT_THROW(handle_->peekAt(1), dhcp_ddns::NcrSenderError);
// Trying to send a NCR when not in send mode should fail.
dhcp_ddns::NameChangeRequestPtr ncr = buildTestNcr();
- EXPECT_THROW(sendRequest(ncr), D2ClientError);
+ EXPECT_THROW(handle_->sendRequest(ncr), D2ClientError);
// Place sender in send mode.
- ASSERT_NO_THROW(startSender(getErrorHandler()));
- ASSERT_TRUE(amSending());
+ ASSERT_NO_THROW(handle_->startSender(getErrorHandler()));
+ ASSERT_TRUE(handle_->amSending());
// Send should succeed now.
- ASSERT_NO_THROW(sendRequest(ncr));
+ ASSERT_NO_THROW(handle_->sendRequest(ncr));
// Queue should have 1 entry.
- EXPECT_EQ(1, getQueueSize());
+ EXPECT_EQ(1, handle_->getQueueSize());
// Attempt to fetch the entry we just queued.
dhcp_ddns::NameChangeRequestPtr ncr2;
- ASSERT_NO_THROW(ncr2 = peekAt(0));
+ ASSERT_NO_THROW(ncr2 = handle_->peekAt(0));
// Verify what we queued matches what we fetched.
EXPECT_TRUE(*ncr == *ncr2);
// Clearing the queue while in send mode should fail.
- ASSERT_THROW(clearQueue(), dhcp_ddns::NcrSenderError);
+ ASSERT_THROW(handle_->clearQueue(), dhcp_ddns::NcrSenderError);
// We should still have 1 in the queue.
- EXPECT_EQ(1, getQueueSize());
+ EXPECT_EQ(1, handle_->getQueueSize());
// Get out of send mode.
- ASSERT_NO_THROW(stopSender());
- ASSERT_FALSE(amSending());
+ ASSERT_NO_THROW(handle_->stopSender());
+ ASSERT_FALSE(handle_->amSending());
// Clear queue should succeed now.
- ASSERT_NO_THROW(clearQueue());
- EXPECT_EQ(0, getQueueSize());
+ ASSERT_NO_THROW(handle_->clearQueue());
+ EXPECT_EQ(0, handle_->getQueueSize());
}
/// @brief Checks that D2ClientMgr can send with a UDP sender and
enableDdns("127.0.0.1", 530001, dhcp_ddns::NCR_UDP);
// Trying to fetch the select-fd when not sending should fail.
- ASSERT_THROW(getSelectFd(), D2ClientError);
+ ASSERT_THROW(handle_->getSelectFd(), D2ClientError);
// Place sender in send mode.
- ASSERT_NO_THROW(startSender(getErrorHandler()));
+ ASSERT_NO_THROW(handle_->startSender(getErrorHandler()));
// select_fd should evaluate to NOT ready to read.
selectCheck(false);
// Build a test request and send it.
dhcp_ddns::NameChangeRequestPtr ncr = buildTestNcr();
- ASSERT_NO_THROW(sendRequest(ncr));
+ ASSERT_NO_THROW(handle_->sendRequest(ncr));
// select_fd should evaluate to ready to read.
selectCheck(true);
// Call service handler.
- runReadyIO();
+ handle_->runReadyIO();
// select_fd should evaluate to not ready to read.
selectCheck(false);
// Place sender in send mode using an external IO service.
asiolink::IOServicePtr io_service(new IOService());
- ASSERT_NO_THROW(startSender(getErrorHandler(), io_service));
+ ASSERT_NO_THROW(handle_->startSender(getErrorHandler(), io_service));
// select_fd should evaluate to NOT ready to read.
selectCheck(false);
// Build a test request and send it.
dhcp_ddns::NameChangeRequestPtr ncr = buildTestNcr();
- ASSERT_NO_THROW(sendRequest(ncr));
+ ASSERT_NO_THROW(handle_->sendRequest(ncr));
// select_fd should evaluate to ready to read.
selectCheck(true);
// Call service handler.
- runReadyIO();
+ handle_->runReadyIO();
// select_fd should evaluate to not ready to read.
selectCheck(false);
// Explicitly stop the sender. This ensures the sender's
// ASIO socket is closed prior to the local io_service
// instance goes out of scope.
- ASSERT_NO_THROW(stopSender());
+ ASSERT_NO_THROW(handle_->stopSender());
}
/// @brief Checks that D2ClientMgr can send with a UDP sender and
// Place sender in send mode using an external IO service.
asiolink::IOServicePtr io_service(new IOService());
- ASSERT_NO_THROW(startSender(getErrorHandler(), io_service));
+ ASSERT_NO_THROW(handle_->startSender(getErrorHandler(), io_service));
// select_fd should evaluate to NOT ready to read.
selectCheck(false);
// Build a test request and send it.
dhcp_ddns::NameChangeRequestPtr ncr = buildTestNcr();
- ASSERT_NO_THROW(sendRequest(ncr));
+ ASSERT_NO_THROW(handle_->sendRequest(ncr));
// select_fd should evaluate to ready to read.
selectCheck(true);
// Call service handler.
- runReadyIO();
+ handle_->runReadyIO();
// select_fd should evaluate to not ready to read.
selectCheck(false);
// Explicitly stop the sender. This ensures the sender's
// ASIO socket is closed prior to the local io_service
// instance goes out of scope.
- ASSERT_NO_THROW(stopSender());
+ ASSERT_NO_THROW(handle_->stopSender());
}
-
/// @brief Checks that D2ClientMgr invokes the client error handler
/// when send errors occur.
TEST_F(D2ClientMgrTest, udpSendErrorHandler) {
// Enable DDNS with server at 127.0.0.1/prot 53001 via UDP.
// Place sender in send mode.
enableDdns("127.0.0.1", 530001, dhcp_ddns::NCR_UDP);
- ASSERT_NO_THROW(startSender(getErrorHandler()));
+ ASSERT_NO_THROW(handle_->startSender(getErrorHandler()));
// Simulate a failed response in the send call back. This should
// cause the error handler to get invoked.
- simulate_send_failure_ = true;
+ handle_->simulate_send_failure_ = true;
// Verify error count is zero.
ASSERT_EQ(0, error_handler_count_);
// Send a test request.
dhcp_ddns::NameChangeRequestPtr ncr = buildTestNcr();
- ASSERT_NO_THROW(sendRequest(ncr));
+ ASSERT_NO_THROW(handle_->sendRequest(ncr));
// Call the ready handler. This should complete the message with an error.
- ASSERT_NO_THROW(runReadyIO());
+ ASSERT_NO_THROW(handle_->runReadyIO());
// If we executed error handler properly, the error count should one.
ASSERT_EQ(1, error_handler_count_);
}
-
/// @brief Checks that client error handler exceptions are handled gracefully.
TEST_F(D2ClientMgrTest, udpSendErrorHandlerThrow) {
// Enable DDNS with server at 127.0.0.1/prot 53001 via UDP.
// Place sender in send mode.
enableDdns("127.0.0.1", 530001, dhcp_ddns::NCR_UDP);
- ASSERT_NO_THROW(startSender(getErrorHandler()));
+ ASSERT_NO_THROW(handle_->startSender(getErrorHandler()));
// Simulate a failed response in the send call back and
// force a throw in the error handler.
- simulate_send_failure_ = true;
+ handle_->simulate_send_failure_ = true;
error_handler_throw_ = true;
// Verify error count is zero.
// Send a test request.
dhcp_ddns::NameChangeRequestPtr ncr = buildTestNcr();
- ASSERT_NO_THROW(sendRequest(ncr));
+ ASSERT_NO_THROW(handle_->sendRequest(ncr));
// Call the ready handler. This should complete the message with an error.
// The handler should throw but the exception should not escape.
- ASSERT_NO_THROW(runReadyIO());
+ ASSERT_NO_THROW(handle_->runReadyIO());
// If throw flag is false, then we were in the error handler should
// have thrown.
enableDdns("127.0.0.1", 530001, dhcp_ddns::NCR_UDP);
// Place sender in send mode.
- ASSERT_NO_THROW(startSender(getErrorHandler()));
+ ASSERT_NO_THROW(handle_->startSender(getErrorHandler()));
// Queue three messages.
for (unsigned i = 0; i < 3; ++i) {
dhcp_ddns::NameChangeRequestPtr ncr = buildTestNcr();
- ASSERT_NO_THROW(sendRequest(ncr));
+ ASSERT_NO_THROW(handle_->sendRequest(ncr));
}
// Make sure queue count is correct.
- EXPECT_EQ(3, getQueueSize());
+ EXPECT_EQ(3, handle_->getQueueSize());
// select_fd should evaluate to ready to read.
selectCheck(true);
IfaceMgr::instance().receive4(0, 0);
// Verify the callback handler was invoked, no errors counted.
- EXPECT_EQ(2, getQueueSize());
- ASSERT_EQ(1, callback_count_);
+ EXPECT_EQ(2, handle_->getQueueSize());
+ ASSERT_EQ(1, handle_->callback_count_);
ASSERT_EQ(0, error_handler_count_);
// Stop the sender. This should complete the second message but leave
// the third in the queue.
- ASSERT_NO_THROW(stopSender());
- EXPECT_EQ(1, getQueueSize());
- ASSERT_EQ(2, callback_count_);
+ ASSERT_NO_THROW(handle_->stopSender());
+ EXPECT_EQ(1, handle_->getQueueSize());
+ ASSERT_EQ(2, handle_->callback_count_);
ASSERT_EQ(0, error_handler_count_);
// Calling receive again should have no affect.
IfaceMgr::instance().receive4(0, 0);
- EXPECT_EQ(1, getQueueSize());
- ASSERT_EQ(2, callback_count_);
+ EXPECT_EQ(1, handle_->getQueueSize());
+ ASSERT_EQ(2, handle_->callback_count_);
ASSERT_EQ(0, error_handler_count_);
}
// Enable DDNS with server at 127.0.0.1/prot 53001 via UDP.
// Place sender in send mode.
enableDdns("127.0.0.1", 530001, dhcp_ddns::NCR_UDP);
- ASSERT_NO_THROW(startSender(getErrorHandler()));
+ ASSERT_NO_THROW(handle_->startSender(getErrorHandler()));
// Send a test request.
for (unsigned i = 0; i < 3; ++i) {
dhcp_ddns::NameChangeRequestPtr ncr = buildTestNcr();
- ASSERT_NO_THROW(sendRequest(ncr));
+ ASSERT_NO_THROW(handle_->sendRequest(ncr));
}
- ASSERT_EQ(3, getQueueSize());
+ ASSERT_EQ(3, handle_->getQueueSize());
// Call the ready handler. This should complete the first message
// and initiate sending the second message.
- ASSERT_NO_THROW(runReadyIO());
+ ASSERT_NO_THROW(handle_->runReadyIO());
// Queue count should have gone down by 1.
- ASSERT_EQ(2, getQueueSize());
+ ASSERT_EQ(2, handle_->getQueueSize());
// Suspend updates. This should disable updates and stop the sender.
- ASSERT_NO_THROW(suspendUpdates());
+ ASSERT_NO_THROW(handle_->suspendUpdates());
- EXPECT_FALSE(ddnsEnabled());
- EXPECT_FALSE(amSending());
+ EXPECT_FALSE(handle_->ddnsEnabled());
+ EXPECT_FALSE(handle_->amSending());
// Stopping the sender should have completed the second message's
// in-progress send, so queue size should be 1.
- ASSERT_EQ(1, getQueueSize());
+ ASSERT_EQ(1, handle_->getQueueSize());
}
/// @brief Tests that invokeErrorHandler does not fail if there is no handler.
TEST_F(D2ClientMgrTest, missingErrorHandler) {
// Ensure we aren't in send mode.
- ASSERT_FALSE(ddnsEnabled());
- ASSERT_FALSE(amSending());
+ ASSERT_FALSE(handle_->ddnsEnabled());
+ ASSERT_FALSE(handle_->amSending());
// There is no error handler at this point, so invoking should not throw.
dhcp_ddns::NameChangeRequestPtr ncr;
- ASSERT_NO_THROW(invokeClientErrorHandler(dhcp_ddns::NameChangeSender::ERROR,
- ncr));
+ ASSERT_NO_THROW(handle_->invokeClientErrorHandler(dhcp_ddns::NameChangeSender::ERROR,
+ ncr));
// Verify we didn't invoke the error handler, error count is zero.
ASSERT_EQ(0, error_handler_count_);