summaryrefslogtreecommitdiffstats
path: root/src/lib/dhcp/tests/iface_mgr_test_config.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/dhcp/tests/iface_mgr_test_config.h')
-rw-r--r--src/lib/dhcp/tests/iface_mgr_test_config.h274
1 files changed, 274 insertions, 0 deletions
diff --git a/src/lib/dhcp/tests/iface_mgr_test_config.h b/src/lib/dhcp/tests/iface_mgr_test_config.h
new file mode 100644
index 0000000..26167e8
--- /dev/null
+++ b/src/lib/dhcp/tests/iface_mgr_test_config.h
@@ -0,0 +1,274 @@
+// Copyright (C) 2014-2020 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef IFACE_MGR_TEST_CONFIG_H
+#define IFACE_MGR_TEST_CONFIG_H
+
+#include <asiolink/io_address.h>
+#include <dhcp/iface_mgr.h>
+#include <boost/noncopyable.hpp>
+
+namespace isc {
+namespace dhcp {
+namespace test {
+
+//@{
+/// @brief Index of the lo fake interface.
+const uint32_t LO_INDEX = 0;
+
+/// @brief Index of the eth0 fake interface.
+const uint32_t ETH0_INDEX = 1;
+
+/// @brief Index of the eth1 fake interface.
+const uint32_t ETH1_INDEX = 2;
+
+/// @brief Index of the eth1961 fake interface.
+const uint32_t ETH1961_INDEX = 1962;
+//@}
+
+///
+/// @name Set of structures describing interface flags.
+///
+/// These flags encapsulate the boolean type to pass the flags values
+/// to @c IfaceMgrTestConfig methods. If the values passed to these methods
+/// were not encapsulated by the types defined here, the API would become
+/// prone to errors like swapping parameters being passed to specific functions.
+/// For example, in the call to @c IfaceMgrTestConfig::setIfaceFlags:
+/// @code
+/// IfaceMgrTestConfig test_config(true);
+/// test_config.setIfaceFlags("eth1", false, false, true, false, false);
+/// @endcode
+///
+/// it is quite likely that the developer by mistake swaps the values and
+/// assigns them to wrong flags. When the flags are encapsulated with dedicated
+/// structs, the compiler will return an error if values are swapped. For
+/// example:
+/// @code
+/// IfaceMgrTestConfig test_config(true);
+/// test_config.setIfaceFlags("eth1", FlagLoopback(false), FlagUp(false),
+/// FlagRunning(true), FlagInactive4(false),
+/// FlagInactive6(false));
+/// @endcode
+/// will succeed, but the following code will result in the compilation error
+/// and thus protect a developer from making an error:
+/// @code
+/// IfaceMgrTestConfig test_config(true);
+/// test_config.setIfaceFlags("eth1", FlagLoopback(false),
+/// FlagRunning(true), FlagUp(false),
+/// FlagInactive4(false), FlagInactive6(false));
+/// @endcode
+///
+//@{
+/// @brief Structure describing the loopback interface flag.
+struct FlagLoopback {
+ explicit FlagLoopback(bool flag) : flag_(flag) { }
+ bool flag_;
+};
+
+/// @brief Structure describing the up interface flag.
+struct FlagUp {
+ explicit FlagUp(bool flag) : flag_(flag) { }
+ bool flag_;
+};
+
+/// @brief Structure describing the running interface flag.
+struct FlagRunning {
+ explicit FlagRunning(bool flag) : flag_(flag) { }
+ bool flag_;
+};
+
+/// @brief Structure describing the inactive4 interface flag.
+struct FlagInactive4 {
+ explicit FlagInactive4(bool flag) : flag_(flag) { }
+ bool flag_;
+};
+
+/// @brief Structure describing the inactive6 interface flag.
+struct FlagInactive6 {
+ explicit FlagInactive6(bool flag) : flag_(flag) { }
+ bool flag_;
+};
+//@}
+
+/// @brief Convenience class for configuring @c IfaceMgr for unit testing.
+///
+/// This class is used by various unit tests which test the code relaying
+/// on IfaceMgr. The use of this class is not limited to libdhcp++ validation.
+/// There are other libraries and applications (e.g. DHCP servers) which
+/// depend on @c IfaceMgr.
+///
+/// During the normal operation, the @c IfaceMgr detects interfaces present
+/// on the machine where it is running. It also provides the means for
+/// applications to open sockets on these interfaces and perform other
+/// IO operations. This however creates dependency of the applications
+/// using @c IfaceMgr on the physical properties of the system and effectively
+/// makes it very hard to unit test the dependent code.
+///
+/// Unit tests usually require that @c IfaceMgr holds a list of well known
+/// interfaces with the well known set of IP addresses and other properties
+/// (a.k.a. interface flags). The solution which works for many test scenarios
+/// is to provide a set of well known fake interfaces, by bypassing the
+/// standard interface detection procedure and manually adding @c Iface objects
+/// which encapsulate the fake interfaces. As a consequence, it becomes
+/// impossible to test IO operations (e.g. sending packets) because real sockets
+/// can't be opened on these interfaces. The @c PktFilterTestStub class
+/// is used by this class to mimic behavior of IO operations on fake sockets.
+///
+/// This class provides a set of convenience functions that should be called
+/// by unit tests to configure the @c IfaceMgr with fake interfaces.
+///
+/// The class allows the caller to create custom fake interfaces (with custom
+/// IPv4 and IPv6 addresses, flags etc.), but it also provides a default
+/// test configuration for interfaces as follows:
+/// - lo #0
+/// - 127.0.0.1
+/// - ::1
+/// - eth0 #1
+/// - 10.0.0.1
+/// - fe80::3a60:77ff:fed5:cdef
+/// - 2001:db8:1::1
+/// - eth1 #2
+/// - 192.0.2.3
+/// - fe80::3a60:77ff:fed5:abcd
+/// - eth1961 #1962
+/// - 198.51.100.1
+/// - fe80::3a60:77ff:fed5:9876
+///
+/// For all interfaces the following flags are set:
+/// - multicast
+/// - up
+/// - running
+class IfaceMgrTestConfig : public boost::noncopyable {
+public:
+
+ /// @brief Constructor.
+ ///
+ /// It closes all sockets opened by @c IfaceMgr and removes all interfaces
+ /// being used by @c IfaceMgr.
+ IfaceMgrTestConfig(const bool default_config = false);
+
+ /// @brief Destructor.
+ ///
+ /// Closes all currently opened sockets, removes current interfaces and
+ /// sets the default packet filtering classes. The default packet filtering
+ /// classes are used for IO operations on real sockets/interfaces.
+ /// Receiver is stopped.
+ ///
+ /// Destructor also re-detects real interfaces.
+ ~IfaceMgrTestConfig();
+
+ /// @brief Adds new IPv4 or IPv6 address to the interface.
+ ///
+ /// @param iface_name Name of the interface on which new address should
+ /// be configured.
+ /// @param address IPv4 or IPv6 address to be configured on the interface.
+ void addAddress(const std::string& iface_name,
+ const asiolink::IOAddress& address);
+
+ /// @brief Configures new interface for the @c IfaceMgr.
+ ///
+ /// @param iface Object encapsulating interface to be added.
+ void addIface(const IfacePtr& iface);
+
+ /// @brief Configures new interface for the @c IfaceMgr.
+ ///
+ /// @param name Name of the new interface.
+ /// @param ifindex Index for a new interface.
+ void addIface(const std::string& name, const int ifindex);
+
+ /// @brief Create an object representing interface.
+ ///
+ /// Apart from creating an interface, this function also sets the
+ /// interface flags:
+ /// - loopback flag if interface name is "lo"
+ /// - up always true
+ /// - running always true
+ /// - inactive4 set to false for non-loopback interface
+ /// - inactive6 set to false for non-loopback interface
+ /// - multicast always to true
+ /// - broadcast always to false
+ ///
+ /// If one needs to modify the default flag settings, the setIfaceFlags
+ /// function should be used.
+ ///
+ /// @param name A name of the interface to be created.
+ /// @param ifindex An index of the interface to be created.
+ ///
+ /// @return An object representing interface.
+ static IfacePtr createIface(const std::string& name, const int ifindex);
+
+ /// @brief Creates a default (example) set of fake interfaces.
+ void createIfaces();
+
+ /// @brief Returns currently used packet filter for DHCPv4.
+ PktFilterPtr getPacketFilter4() const {
+ return (packet_filter4_);
+ }
+
+ /// @brief Sets the direct response capability for current packet filter.
+ ///
+ /// The test uses stub implementation of packet filter object. It is
+ /// possible to configure that object to report having a capability
+ /// to directly respond to clients which don't have an address yet.
+ /// This function sets this property for packet filter object.
+ ///
+ /// @param direct_resp Value to be set.
+ ///
+ /// @throw isc::Unexpected if unable to set the property.
+ void setDirectResponse(const bool direct_resp);
+
+ /// @brief Sets various flags on the specified interface.
+ ///
+ /// This function configures interface with new values for flags.
+ ///
+ /// @param name Interface name.
+ /// @param loopback Specifies if interface is a loopback interface.
+ /// @param up Specifies if the interface is up.
+ /// @param running Specifies if the interface is running.
+ /// @param inactive4 Specifies if the interface is inactive for V4
+ /// traffic, i.e. @c IfaceMgr opens V4 sockets on this interface.
+ /// @param inactive6 Specifies if the interface is inactive for V6
+ /// traffic, i.e. @c IfaceMgr opens V6 sockets on this interface.
+ void setIfaceFlags(const std::string& name,
+ const FlagLoopback& loopback,
+ const FlagUp& up,
+ const FlagRunning& running,
+ const FlagInactive4& inactive4,
+ const FlagInactive6& inactive6);
+
+ /// @brief Checks if socket of the specified family is opened on interface.
+ ///
+ /// @param iface_name Interface name.
+ /// @param family One of: AF_INET or AF_INET6
+ bool socketOpen(const std::string& iface_name, const int family) const;
+
+ /// @brief Checks is socket is opened on the interface and bound to a
+ /// specified address.
+ ///
+ /// @param iface_name Interface name.
+ /// @param address Address to which the socket is bound.
+ bool socketOpen(const std::string& iface_name,
+ const std::string& address) const;
+
+ /// @brief Checks if unicast socket is opened on interface.
+ ///
+ /// @param iface_name Interface name.
+ bool unicastOpen(const std::string& iface_name) const;
+
+
+private:
+ /// @brief Currently used packet filter for DHCPv4.
+ PktFilterPtr packet_filter4_;
+
+ /// @brief Currently used packet filter for DHCPv6.
+ PktFilter6Ptr packet_filter6_;
+};
+
+};
+};
+};
+
+#endif // IFACE_MGR_TEST_CONFIG_H