Commit 09811212 authored by Marcin Siodelski's avatar Marcin Siodelski
Browse files

[2765] Moved the PktFilter test fixture class to the common class.

parent 4507742b
......@@ -49,6 +49,7 @@ libdhcp___unittests_SOURCES += option_vendor_unittest.cc
libdhcp___unittests_SOURCES += pkt4_unittest.cc
libdhcp___unittests_SOURCES += pkt6_unittest.cc
libdhcp___unittests_SOURCES += pkt_filter_inet_unittest.cc
libdhcp___unittests_SOURCES += pkt_filter_test_utils.h pkt_filter_test_utils.cc
if OS_LINUX
libdhcp___unittests_SOURCES += pkt_filter_lpf_unittest.cc
......
......@@ -17,6 +17,7 @@
#include <dhcp/iface_mgr.h>
#include <dhcp/pkt4.h>
#include <dhcp/pkt_filter_inet.h>
#include <dhcp/tests/pkt_filter_test_utils.h>
#include <gtest/gtest.h>
......@@ -32,63 +33,12 @@ const uint16_t PORT = 10067;
/// Size of the buffer holding received packets.
const size_t RECV_BUF_SIZE = 2048;
/// This class handles has simple algorithm checking
/// presence of loopback interface and initializing
/// its index.
class PktFilterInetTest : public ::testing::Test {
// Test fixture class inherits from the class common for all packet
// filter tests.
class PktFilterInetTest : public isc::dhcp::test::PktFilterTest {
public:
/// @brief Constructor
///
/// This constructor initializes socket_ member to a negative value.
/// Explcit initialization is performed here because some of the
/// tests do not initialize this value. In such cases, destructor
/// could invoke close() on uninitialized socket descriptor which
/// would result in errors being reported by Valgrind.
PktFilterInetTest()
: socket_(-1) {
// Initialize ifname_ and ifindex_.
loInit();
}
/// @brief Destructor
///
/// Closes open socket (if any).
~PktFilterInetTest() {
// Cleanup after each test. This guarantees
// that the socket does not hang after a test.
if (socket_ >= 0) {
close(socket_);
}
PktFilterInetTest() : PktFilterTest(PORT) {
}
/// @brief Detect loopback interface.
///
/// @todo this function will be removed once cross-OS interface
/// detection is implemented
void loInit() {
if (if_nametoindex("lo") > 0) {
ifname_ = "lo";
ifindex_ = if_nametoindex("lo");
} else if (if_nametoindex("lo0") > 0) {
ifname_ = "lo0";
ifindex_ = if_nametoindex("lo0");
} else {
std::cout << "Failed to detect loopback interface. Neither "
<< "lo nor lo0 worked. Giving up." << std::endl;
FAIL();
}
}
std::string ifname_; ///< Loopback interface name
uint16_t ifindex_; ///< Loopback interface index.
int socket_; ///< Socket descriptor.
};
// This test verifies that the PktFilterInet class reports its lack
......@@ -112,14 +62,16 @@ TEST_F(PktFilterInetTest, openSocket) {
// Try to open socket.
PktFilterInet pkt_filter;
socket_ = pkt_filter.openSocket(iface, addr, PORT, false, false).sockfd_;
sock_info_ = pkt_filter.openSocket(iface, addr, PORT,
false, false);
// Check that socket has been opened.
ASSERT_GE(socket_, 0);
ASSERT_GE(sock_info_.sockfd_, 0);
// Verify that the socket belongs to AF_INET family.
sockaddr_in sock_address;
socklen_t sock_address_len = sizeof(sock_address);
ASSERT_EQ(0, getsockname(socket_, reinterpret_cast<sockaddr*>(&sock_address),
ASSERT_EQ(0, getsockname(sock_info_.sockfd_,
reinterpret_cast<sockaddr*>(&sock_address),
&sock_address_len));
EXPECT_EQ(AF_INET, sock_address.sin_family);
......@@ -133,7 +85,8 @@ TEST_F(PktFilterInetTest, openSocket) {
// Verify that the socket has SOCK_DGRAM type.
int sock_type;
socklen_t sock_type_len = sizeof(sock_type);
ASSERT_EQ(0, getsockopt(socket_, SOL_SOCKET, SO_TYPE, &sock_type, &sock_type_len));
ASSERT_EQ(0, getsockopt(sock_info_.sockfd_, SOL_SOCKET, SO_TYPE,
&sock_type, &sock_type_len));
EXPECT_EQ(SOCK_DGRAM, sock_type);
}
......@@ -170,27 +123,27 @@ TEST_F(PktFilterInetTest, send) {
// Open socket. We don't check that the socket has appropriate
// options and family set because we have checked that in the
// openSocket test already.
socket_ = pkt_filter.openSocket(iface, addr, PORT, false, false).sockfd_;
ASSERT_GE(socket_, 0);
sock_info_ = pkt_filter.openSocket(iface, addr, PORT, false, false);
ASSERT_GE(sock_info_.sockfd_, 0);
// Send the packet over the socket.
ASSERT_NO_THROW(pkt_filter.send(iface, socket_, pkt));
ASSERT_NO_THROW(pkt_filter.send(iface, sock_info_.sockfd_, pkt));
// Read the data from socket.
fd_set readfds;
FD_ZERO(&readfds);
FD_SET(socket_, &readfds);
FD_SET(sock_info_.sockfd_, &readfds);
struct timeval timeout;
timeout.tv_sec = 5;
timeout.tv_usec = 0;
int result = select(socket_ + 1, &readfds, NULL, NULL, &timeout);
int result = select(sock_info_.sockfd_ + 1, &readfds, NULL, NULL, &timeout);
// We should receive some data from loopback interface.
ASSERT_GT(result, 0);
// Get the actual data.
uint8_t rcv_buf[RECV_BUF_SIZE];
result = recv(socket_, rcv_buf, RECV_BUF_SIZE, 0);
result = recv(sock_info_.sockfd_, rcv_buf, RECV_BUF_SIZE, 0);
ASSERT_GT(result, 0);
// Create the DHCPv4 packet from the received data.
......@@ -249,15 +202,14 @@ TEST_F(PktFilterInetTest, receive) {
// Open socket. We don't check that the socket has appropriate
// options and family set because we have checked that in the
// openSocket test already.
socket_ = pkt_filter.openSocket(iface, addr, PORT, false, false).sockfd_;
ASSERT_GE(socket_, 0);
sock_info_ = pkt_filter.openSocket(iface, addr, PORT, false, false);
ASSERT_GE(sock_info_.sockfd_, 0);
// Send the packet over the socket.
ASSERT_NO_THROW(pkt_filter.send(iface, socket_, pkt));
ASSERT_NO_THROW(pkt_filter.send(iface, sock_info_.sockfd_, pkt));
// Receive the packet.
SocketInfo socket_info(IOAddress("127.0.0.1"), PORT, socket_);
Pkt4Ptr rcvd_pkt = pkt_filter.receive(iface, socket_info);
Pkt4Ptr rcvd_pkt = pkt_filter.receive(iface, sock_info_);
// Check that the packet has been correctly received.
ASSERT_TRUE(rcvd_pkt);
......
......@@ -18,6 +18,7 @@
#include <dhcp/pkt4.h>
#include <dhcp/pkt_filter_lpf.h>
#include <dhcp/protocol_util.h>
#include <dhcp/tests/pkt_filter_test_utils.h>
#include <util/buffer.h>
#include <gtest/gtest.h>
......@@ -36,66 +37,12 @@ const uint16_t PORT = 10067;
/// Size of the buffer holding received packets.
const size_t RECV_BUF_SIZE = 2048;
/// This class handles has simple algorithm checking
/// presence of loopback interface and initializing
/// its index.
class PktFilterLPFTest : public ::testing::Test {
// Test fixture class inherits from the class common for all packet
// filter tests.
class PktFilterLPFTest : public isc::dhcp::test::PktFilterTest {
public:
/// @brief Constructor
///
/// This constructor initializes sock_info_ structure to a default value.
/// The socket descriptors should be set to a negative value to indicate
/// that no socket has been opened. Specific tests will reinitialize this
/// structure with the values of the open sockets. For non-negative socket
/// descriptors, the class destructor will close associated sockets.
PktFilterLPFTest()
: sock_info_(IOAddress("127.0.0.1"), PORT, -1, -1) {
// Initialize ifname_ and ifindex_.
loInit();
}
/// @brief Destructor
///
/// Closes open sockets (if any).
~PktFilterLPFTest() {
// Cleanup after each test. This guarantees
// that the sockets do not hang after a test.
if (sock_info_.sockfd_ >= 0) {
close(sock_info_.sockfd_);
}
if (sock_info_.fallbackfd_ >=0) {
close(sock_info_.fallbackfd_);
}
}
/// @brief Detect loopback interface.
///
/// @todo this function will be removed once cross-OS interface
/// detection is implemented
void loInit() {
if (if_nametoindex("lo") > 0) {
ifname_ = "lo";
ifindex_ = if_nametoindex("lo");
} else if (if_nametoindex("lo0") > 0) {
ifname_ = "lo0";
ifindex_ = if_nametoindex("lo0");
} else {
std::cout << "Failed to detect loopback interface. Neither "
<< "lo nor lo0 worked. Giving up." << std::endl;
FAIL();
}
PktFilterLPFTest() : PktFilterTest(PORT) {
}
std::string ifname_; ///< Loopback interface name
uint16_t ifindex_; ///< Loopback interface index.
SocketInfo sock_info_; ///< A structure holding socket information.
};
// This test verifies that the PktFilterLPF class reports its capability
......
// Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include <dhcp/pkt4.h>
#include <dhcp/tests/pkt_filter_test_utils.h>
namespace isc {
namespace dhcp {
namespace test {
PktFilterTest::PktFilterTest(const uint16_t port)
: port_(port),
sock_info_(isc::asiolink::IOAddress("127.0.0.1"), port, -1, -1) {
// Initialize ifname_ and ifindex_.
loInit();
}
PktFilterTest::~PktFilterTest() {
// Cleanup after each test. This guarantees
// that the sockets do not hang after a test.
if (sock_info_.sockfd_ >= 0) {
close(sock_info_.sockfd_);
}
if (sock_info_.fallbackfd_ >=0) {
close(sock_info_.fallbackfd_);
}
}
void
PktFilterTest::loInit() {
if (if_nametoindex("lo") > 0) {
ifname_ = "lo";
ifindex_ = if_nametoindex("lo");
} else if (if_nametoindex("lo0") > 0) {
ifname_ = "lo0";
ifindex_ = if_nametoindex("lo0");
} else {
std::cout << "Failed to detect loopback interface. Neither "
<< "lo nor lo0 worked. Giving up." << std::endl;
FAIL();
}
}
void
PktFilterTest::testDgramSocket(const int sock) const {
// Check that socket has been opened.
ASSERT_GE(sock, 0);
// Verify that the socket belongs to AF_INET family.
sockaddr_in sock_address;
socklen_t sock_address_len = sizeof(sock_address);
ASSERT_EQ(0, getsockname(sock,
reinterpret_cast<sockaddr*>(&sock_address),
&sock_address_len));
EXPECT_EQ(AF_INET, sock_address.sin_family);
// Verify that the socket is bound the appropriate address.
const std::string bind_addr(inet_ntoa(sock_address.sin_addr));
EXPECT_EQ("127.0.0.1", bind_addr);
// Verify that the socket is bound to appropriate port.
EXPECT_EQ(port_, ntohs(sock_address.sin_port));
// Verify that the socket has SOCK_DGRAM type.
int sock_type;
socklen_t sock_type_len = sizeof(sock_type);
ASSERT_EQ(0, getsockopt(sock, SOL_SOCKET, SO_TYPE,
&sock_type, &sock_type_len));
EXPECT_EQ(SOCK_DGRAM, sock_type);
}
bool
PktFilterStub::isDirectResponseSupported() const {
return (true);
}
SocketInfo
PktFilterStub::openSocket(const Iface&,
const isc::asiolink::IOAddress& addr,
const uint16_t port, const bool, const bool) {
return (SocketInfo(addr, port, 0));
}
Pkt4Ptr
PktFilterStub::receive(const Iface&, const SocketInfo&) {
return Pkt4Ptr();
}
int
PktFilterStub::send(const Iface&, uint16_t, const Pkt4Ptr&) {
return (0);
}
} // end of isc::dhcp::test namespace
} // end of isc::dhcp namespace
} // end of isc namespace
// Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#ifndef PKT_FILTER_TEST_UTILS_H
#define PKT_FILTER_TEST_UTILS_H
#include <asiolink/io_address.h>
#include <dhcp/iface_mgr.h>
#include <dhcp/pkt_filter.h>
#include <gtest/gtest.h>
namespace isc {
namespace dhcp {
namespace test {
/// @brief Test fixture class for testing classes derived from PktFilter class.
///
/// This class implements a simple algorithm checking presence of the loopback
/// interface and initializing its index. It assumes that the loopback interface
/// name is one of 'lo' or 'lo0'. If none of those interfaces is found, the
/// constructor will report a failure.
///
/// @todo The interface detection algorithm should be more generic. This will
/// be possible once the cross-OS interface detection is implemented.
class PktFilterTest : public ::testing::Test {
public:
/// @brief Constructor
///
/// This constructor initializes sock_info_ structure to a default value.
/// The socket descriptors should be set to a negative value to indicate
/// that no socket has been opened. Specific tests will reinitialize this
/// structure with the values of the open sockets. For non-negative socket
/// descriptors, the class destructor will close associated sockets.
PktFilterTest(const uint16_t port);
/// @brief Destructor
///
/// Closes open sockets (if any).
virtual ~PktFilterTest();
/// @brief Detect loopback interface.
///
/// @todo this function will be removed once cross-OS interface
/// detection is implemented
void loInit();
/// @brief Test that the datagram socket is opened correctly.
///
/// This function is used by multiple tests.
///
/// @param sock A descriptor of the open socket.
void testDgramSocket(const int sock) const;
std::string ifname_; ///< Loopback interface name
uint16_t ifindex_; ///< Loopback interface index.
uint16_t port_; ///< A port number used for the test.
isc::dhcp::SocketInfo sock_info_; ///< A structure holding socket information.
};
/// @brief A stub implementation of the PktFilter class.
///
/// This class implements abstract methods of the @c isc::dhcp::test::PktFilter
/// class. It is used by unit tests, which test protected methods of the
/// @c isc::dhcp::test::PktFilter class. The implemented abstract methods are
/// no-op.
class PktFilterStub : public PktFilter {
public:
/// @brief Checks if the direct DHCPv4 response is supported.
///
/// This function checks if the direct response capability is supported,
/// i.e. if the server can respond to the client which doesn't have an
/// address yet. For this dummy class, the true is alaways returned.
///
/// @return always true.
virtual bool isDirectResponseSupported() const;
/// @brief Simulate opening of the socket.
///
/// This function simulates openinga primary socket. In reality, it doesn't
/// open a socket but the socket descriptor returned in the SocketInfo
/// structure is always set to 0.
///
/// @param iface An interface descriptor.
/// @param addr Address on the interface to be used to send packets.
/// @param port Port number to bind socket to.
/// @param receive_bcast A flag which indicates if socket should be
/// configured to receive broadcast packets (if true).
/// @param send_bcast A flag which indicates if the socket should be
/// configured to send broadcast packets (if true).
///
/// @note All parameters are ignored.
///
/// @return A SocketInfo structure with the socket descriptor set to 0. The
/// fallback socket descriptor is set to a negative value.
virtual SocketInfo openSocket(const Iface& iface,
const isc::asiolink::IOAddress& addr,
const uint16_t port, const bool, const bool);
/// @brief Simulate reception of the DHCPv4 message.
///
/// @param iface An interface to be used to receive DHCPv4 message.
/// @param sock_info A descriptor of the primary and fallback sockets.
///
/// @note All parameters are ignored.
///
/// @return always a NULL object.
virtual Pkt4Ptr receive(const Iface& iface, const SocketInfo& sock_info);
/// @brief Simulates sending a DHCPv4 message.
///
/// This function does nothing.
///
/// @param iface An interface to be used to send DHCPv4 message.
/// @param port A port used to send a message.
/// @param pkt A DHCPv4 to be sent.
///
/// @note All parameters are ignored.
///
/// @return 0.
virtual int send(const Iface& iface, uint16_t port, const Pkt4Ptr& pkt);
// Change the scope of the protected function so as they can be unit tested.
using PktFilter::openFallbackSocket;
};
}; // end of isc::dhcp::test namespace
}; // end of isc::dhcp namespace
}; // end of isc namespace
#endif // PKT_FILTER_TEST_UTILS_H
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment