|
@@ -5,13 +5,19 @@
|
|
|
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
|
|
#include <config.h>
|
|
|
+
|
|
|
#include <asiolink/io_address.h>
|
|
|
#include <dhcp/pkt4o6.h>
|
|
|
#include <dhcp/pkt6.h>
|
|
|
#include <dhcp/tests/iface_mgr_test_config.h>
|
|
|
+#include <dhcp4/ctrl_dhcp4_srv.h>
|
|
|
#include <dhcp4/dhcp4to6_ipc.h>
|
|
|
+#include <dhcp4/tests/dhcp4_test_utils.h>
|
|
|
#include <dhcpsrv/cfgmgr.h>
|
|
|
#include <dhcpsrv/testutils/dhcp4o6_test_ipc.h>
|
|
|
+#include <hooks/callout_handle.h>
|
|
|
+#include <hooks/hooks_manager.h>
|
|
|
+
|
|
|
#include <gtest/gtest.h>
|
|
|
#include <stdint.h>
|
|
|
|
|
@@ -19,6 +25,7 @@ using namespace isc;
|
|
|
using namespace isc::asiolink;
|
|
|
using namespace isc::dhcp;
|
|
|
using namespace isc::dhcp::test;
|
|
|
+using namespace isc::hooks;
|
|
|
using namespace isc::util;
|
|
|
|
|
|
namespace {
|
|
@@ -30,7 +37,7 @@ const uint16_t TEST_PORT = 32000;
|
|
|
typedef Dhcp4o6TestIpc TestIpc;
|
|
|
|
|
|
/// @brief Test fixture class for DHCPv4 endpoint of DHCPv4o6 IPC.
|
|
|
-class Dhcp4to6IpcTest : public ::testing::Test {
|
|
|
+class Dhcp4to6IpcTest : public Dhcpv4SrvTest {
|
|
|
public:
|
|
|
|
|
|
/// @brief Constructor
|
|
@@ -38,8 +45,16 @@ public:
|
|
|
/// Configures IPC to use a test port. It also provides a fake
|
|
|
/// configuration of interfaces.
|
|
|
Dhcp4to6IpcTest()
|
|
|
- : iface_mgr_test_config_(true) {
|
|
|
+ : Dhcpv4SrvTest(),
|
|
|
+ iface_mgr_test_config_(true) {
|
|
|
configurePort(TEST_PORT);
|
|
|
+ // Install buffer4_receive_callout
|
|
|
+ EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().
|
|
|
+ registerCallout("buffer4_receive",
|
|
|
+ buffer4_receive_callout));
|
|
|
+ // Install buffer4_send_callout
|
|
|
+ EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().
|
|
|
+ registerCallout("buffer4_send", buffer4_send_callout));
|
|
|
}
|
|
|
|
|
|
/// @brief Configure DHCP4o6 port.
|
|
@@ -55,6 +70,42 @@ public:
|
|
|
/// @return Pointer to the instance of the DHCPv4-query Message option.
|
|
|
OptionPtr createDHCPv4MsgOption() const;
|
|
|
|
|
|
+ /// @brief Handler for the buffer4_receive hook
|
|
|
+ ///
|
|
|
+ /// This hook is at the beginning of processPacket
|
|
|
+ ///
|
|
|
+ /// @param callout_handle handle passed by the hooks framework
|
|
|
+ /// @return always 0
|
|
|
+ static int
|
|
|
+ buffer4_receive_callout(CalloutHandle& callout_handle) {
|
|
|
+ callout_handle.getArgument("query4", callback_recv_pkt_);
|
|
|
+ return (0);
|
|
|
+ }
|
|
|
+
|
|
|
+ /// @brief Handler for the buffer4_send hook
|
|
|
+ ///
|
|
|
+ /// This hook is at the end of the DHCPv4o6 packet handler
|
|
|
+ ///
|
|
|
+ /// @param callout_handle handle passed by the hooks framework
|
|
|
+ /// @return always 0
|
|
|
+ static int
|
|
|
+ buffer4_send_callout(CalloutHandle& callout_handle) {
|
|
|
+ callout_handle.getArgument("response4", callback_sent_pkt_);
|
|
|
+ return (0);
|
|
|
+ }
|
|
|
+
|
|
|
+ /// @brief Response Pkt4 shared pointer returned in the receive callout
|
|
|
+ static Pkt4Ptr callback_recv_pkt_;
|
|
|
+
|
|
|
+ /// @brief Response Pkt4 shared pointer returned in the send callout
|
|
|
+ static Pkt4Ptr callback_sent_pkt_;
|
|
|
+
|
|
|
+ /// @brief reference to a controlled server
|
|
|
+ ///
|
|
|
+ /// Dhcp4to6Ipc::handler() uses the instance of the controlled server
|
|
|
+ /// so it has to be build. This reference does this.
|
|
|
+ ControlledDhcpv4Srv srv;
|
|
|
+
|
|
|
private:
|
|
|
|
|
|
/// @brief Provides fake configuration of interfaces.
|
|
@@ -62,6 +113,9 @@ private:
|
|
|
|
|
|
};
|
|
|
|
|
|
+Pkt4Ptr Dhcp4to6IpcTest::callback_recv_pkt_;
|
|
|
+Pkt4Ptr Dhcp4to6IpcTest::callback_sent_pkt_;
|
|
|
+
|
|
|
void
|
|
|
Dhcp4to6IpcTest::configurePort(uint16_t port) {
|
|
|
CfgMgr::instance().getStagingCfg()->setDhcp4o6Port(port);
|
|
@@ -94,6 +148,11 @@ TEST_F(Dhcp4to6IpcTest, invalidPortError) {
|
|
|
// This test verifies that the DHCPv4 endpoint of the DHCPv4o6 IPC can
|
|
|
// receive messages.
|
|
|
TEST_F(Dhcp4to6IpcTest, receive) {
|
|
|
+ // Verify we have a controlled server
|
|
|
+ ControlledDhcpv4Srv* srv = NULL;
|
|
|
+ ASSERT_NO_THROW(srv = ControlledDhcpv4Srv::getInstance());
|
|
|
+ ASSERT_TRUE(srv);
|
|
|
+
|
|
|
// Create instance of the IPC endpoint under test.
|
|
|
Dhcp4to6Ipc& ipc = Dhcp4to6Ipc::instance();
|
|
|
// Create instance of the IPC endpoint being used as a source of messages.
|
|
@@ -110,12 +169,20 @@ TEST_F(Dhcp4to6IpcTest, receive) {
|
|
|
pkt->setRemoteAddr(IOAddress("2001:db8:1::123"));
|
|
|
ASSERT_NO_THROW(pkt->pack());
|
|
|
|
|
|
+ // Reset the received packet
|
|
|
+ Dhcp4to6IpcTest::callback_recv_pkt_.reset();
|
|
|
+
|
|
|
// Send and wait up to 1 second to receive it.
|
|
|
ASSERT_NO_THROW(src_ipc.send(pkt));
|
|
|
ASSERT_NO_THROW(IfaceMgr::instance().receive6(1, 0));
|
|
|
|
|
|
// Make sure that the message has been received.
|
|
|
- Pkt4o6Ptr pkt_received = ipc.getReceived();
|
|
|
+ // The buffer4_receive hook is at the beginning of processPacket
|
|
|
+ // so this proves it was passed to it.
|
|
|
+ Pkt4Ptr pkt4_received = Dhcp4to6IpcTest::callback_recv_pkt_;
|
|
|
+ ASSERT_TRUE(pkt4_received);
|
|
|
+ Pkt4o6Ptr pkt_received =
|
|
|
+ boost::dynamic_pointer_cast<Pkt4o6>(pkt4_received);
|
|
|
ASSERT_TRUE(pkt_received);
|
|
|
Pkt6Ptr pkt6_received = pkt_received->getPkt6();
|
|
|
ASSERT_TRUE(pkt6_received);
|
|
@@ -126,6 +193,11 @@ TEST_F(Dhcp4to6IpcTest, receive) {
|
|
|
// This test verifies that message with multiple DHCPv4 query options
|
|
|
// is rejected.
|
|
|
TEST_F(Dhcp4to6IpcTest, receiveMultipleQueries) {
|
|
|
+ // Verify we have a controlled server
|
|
|
+ ControlledDhcpv4Srv* srv = NULL;
|
|
|
+ ASSERT_NO_THROW(srv = ControlledDhcpv4Srv::getInstance());
|
|
|
+ ASSERT_TRUE(srv);
|
|
|
+
|
|
|
// Create instance of the IPC endpoint under test.
|
|
|
Dhcp4to6Ipc& ipc = Dhcp4to6Ipc::instance();
|
|
|
// Create instance of the IPC endpoint being used as a source of messages.
|
|
@@ -144,14 +216,25 @@ TEST_F(Dhcp4to6IpcTest, receiveMultipleQueries) {
|
|
|
pkt->setRemoteAddr(IOAddress("2001:db8:1::123"));
|
|
|
ASSERT_NO_THROW(pkt->pack());
|
|
|
|
|
|
- // Send message.
|
|
|
+ // Reset the received packet
|
|
|
+ Dhcp4to6IpcTest::callback_recv_pkt_.reset();
|
|
|
+
|
|
|
+ // Send and wait up to 1 second to receive it.
|
|
|
ASSERT_NO_THROW(src_ipc.send(pkt));
|
|
|
- // Reception handler should throw exception.
|
|
|
- EXPECT_THROW(IfaceMgr::instance().receive6(1, 0), Dhcp4o6IpcError);
|
|
|
+ EXPECT_NO_THROW(IfaceMgr::instance().receive6(1, 0));
|
|
|
+
|
|
|
+ // No message should has been sent.
|
|
|
+ Pkt4Ptr pkt4_received = Dhcp4to6IpcTest::callback_recv_pkt_;
|
|
|
+ EXPECT_FALSE(pkt4_received);
|
|
|
}
|
|
|
|
|
|
// This test verifies that message with no DHCPv4 query options is rejected.
|
|
|
TEST_F(Dhcp4to6IpcTest, receiveNoQueries) {
|
|
|
+ // Verify we have a controlled server
|
|
|
+ ControlledDhcpv4Srv* srv = NULL;
|
|
|
+ ASSERT_NO_THROW(srv = ControlledDhcpv4Srv::getInstance());
|
|
|
+ ASSERT_TRUE(srv);
|
|
|
+
|
|
|
// Create instance of the IPC endpoint under test.
|
|
|
Dhcp4to6Ipc& ipc = Dhcp4to6Ipc::instance();
|
|
|
// Create instance of the IPC endpoint being used as a source of messages.
|
|
@@ -167,10 +250,76 @@ TEST_F(Dhcp4to6IpcTest, receiveNoQueries) {
|
|
|
pkt->setRemoteAddr(IOAddress("2001:db8:1::123"));
|
|
|
ASSERT_NO_THROW(pkt->pack());
|
|
|
|
|
|
- // Send message.
|
|
|
+ // Reset the received packet
|
|
|
+ Dhcp4to6IpcTest::callback_recv_pkt_.reset();
|
|
|
+
|
|
|
+ // Send and wait up to 1 second to receive it.
|
|
|
+ ASSERT_NO_THROW(src_ipc.send(pkt));
|
|
|
+ EXPECT_NO_THROW(IfaceMgr::instance().receive6(1, 0));
|
|
|
+
|
|
|
+ // No message should has been sent.
|
|
|
+ Pkt4Ptr pkt4_received = Dhcp4to6IpcTest::callback_recv_pkt_;
|
|
|
+ EXPECT_FALSE(pkt4_received);
|
|
|
+}
|
|
|
+
|
|
|
+// This test verifies that the DHCPv4 endpoint of the DHCPv4o6 IPC can
|
|
|
+// process messages.
|
|
|
+TEST_F(Dhcp4to6IpcTest, process) {
|
|
|
+ // Verify we have a controlled server
|
|
|
+ ControlledDhcpv4Srv* srv = NULL;
|
|
|
+ ASSERT_NO_THROW(srv = ControlledDhcpv4Srv::getInstance());
|
|
|
+ ASSERT_TRUE(srv);
|
|
|
+
|
|
|
+ // Create instance of the IPC endpoint under test.
|
|
|
+ Dhcp4to6Ipc& ipc = Dhcp4to6Ipc::instance();
|
|
|
+ // Create instance of the IPC endpoint being used as a source of messages.
|
|
|
+ TestIpc src_ipc(TEST_PORT, TestIpc::ENDPOINT_TYPE_V6);
|
|
|
+
|
|
|
+ // Open both endpoints.
|
|
|
+ ASSERT_NO_THROW(ipc.open());
|
|
|
+ ASSERT_NO_THROW(src_ipc.open());
|
|
|
+
|
|
|
+ // Create message to be sent over IPC.
|
|
|
+ Pkt6Ptr pkt(new Pkt6(DHCPV6_DHCPV4_QUERY, 1234));
|
|
|
+ pkt->addOption(createDHCPv4MsgOption());
|
|
|
+ pkt->setIface("eth0");
|
|
|
+ pkt->setRemoteAddr(IOAddress("2001:db8:1::123"));
|
|
|
+ ASSERT_NO_THROW(pkt->pack());
|
|
|
+
|
|
|
+ // TODO: put enough in the packet and server config to make it pass
|
|
|
+ // through processPacket, in particular provide a subnet to select
|
|
|
+
|
|
|
+ // Reset the received packet
|
|
|
+ Dhcp4to6IpcTest::callback_recv_pkt_.reset();
|
|
|
+
|
|
|
+ // Send and wait up to 1 second to receive it.
|
|
|
ASSERT_NO_THROW(src_ipc.send(pkt));
|
|
|
- // Reception handler should throw exception.
|
|
|
- EXPECT_THROW(IfaceMgr::instance().receive6(1, 0), Dhcp4o6IpcError);
|
|
|
+ ASSERT_NO_THROW(IfaceMgr::instance().receive6(1, 0));
|
|
|
+
|
|
|
+ // Make sure that the message has been received.
|
|
|
+ Pkt4Ptr pkt4_received = Dhcp4to6IpcTest::callback_recv_pkt_;
|
|
|
+ ASSERT_TRUE(pkt4_received);
|
|
|
+ Pkt4o6Ptr pkt_received =
|
|
|
+ boost::dynamic_pointer_cast<Pkt4o6>(pkt4_received);
|
|
|
+ ASSERT_TRUE(pkt_received);
|
|
|
+ Pkt6Ptr pkt6_received = pkt_received->getPkt6();
|
|
|
+ ASSERT_TRUE(pkt6_received);
|
|
|
+ EXPECT_EQ("eth0", pkt6_received->getIface());
|
|
|
+ EXPECT_EQ("2001:db8:1::123", pkt6_received->getRemoteAddr().toText());
|
|
|
+
|
|
|
+ // Make sure that the message has been processed.
|
|
|
+ // Using the buffer4_send hook
|
|
|
+ Pkt4Ptr pkt4_sent = Dhcp4to6IpcTest::callback_sent_pkt_;
|
|
|
+#if 0
|
|
|
+ ASSERT_TRUE(pkt4_sent);
|
|
|
+ Pkt4o6Ptr pkt_sent = boost::dynamic_pointer_cast<Pkt4o6>(pkt4_sent);
|
|
|
+ ASSERT_TRUE(pkt_sent);
|
|
|
+ Pkt6Ptr pkt6_sent = pkt_sent->getPkt6();
|
|
|
+ ASSERT_TRUE(pkt6_sent);
|
|
|
+ EXPECT_EQ("eth0", pkt6_sent->getIface());
|
|
|
+ EXPECT_EQ("2001:db8:1::123", pkt6_sent->getRemoteAddr().toText());
|
|
|
+ // more tests
|
|
|
+#endif
|
|
|
}
|
|
|
|
|
|
} // end of anonymous namespace
|