ifaces_config_parser_unittest.cc 5.95 KB
Newer Older
1
// Copyright (C) 2015,2017 Internet Systems Consortium, Inc. ("ISC")
2
//
3
4
5
// 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/.
6
7
8
9
10
11
12

#include <config.h>

#include <cc/data.h>
#include <dhcp/tests/iface_mgr_test_config.h>
#include <dhcpsrv/cfgmgr.h>
#include <dhcpsrv/parsers/ifaces_config_parser.h>
13
#include <testutils/test_to_element.h>
14
15
16
17
18
#include <gtest/gtest.h>

using namespace isc::data;
using namespace isc::dhcp;
using namespace isc::dhcp::test;
19
using namespace isc::test;
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55

namespace {

/// @brief Test fixture class for @c IfacesConfigParser
class IfacesConfigParserTest : public ::testing::Test {
protected:

    /// @brief Setup for each test.
    ///
    /// Clears the configuration in the @c CfgMgr.
    virtual void SetUp();

    /// @brief Cleans up after each test.
    ///
    /// Clears the configuration in the @c CfgMgr.
    virtual void TearDown();

};

void
IfacesConfigParserTest::SetUp() {
    CfgMgr::instance().clear();
}

void
IfacesConfigParserTest::TearDown() {
    CfgMgr::instance().clear();
}

// This test checks that the parser correctly parses the list of interfaces
// on which the server should listen.
TEST_F(IfacesConfigParserTest, interfaces) {
    // Creates fake interfaces with fake addresses.
    IfaceMgrTestConfig test_config(true);

    // Configuration with one interface.
56
    std::string config = "{ ""\"interfaces\": [ \"eth0\" ] }";
57
58
59
60

    ElementPtr config_element = Element::fromJSON(config);

    // Parse the configuration.
61
62
    IfacesConfigParser parser(AF_INET);
    CfgIfacePtr cfg_iface = CfgMgr::instance().getStagingCfg()->getCfgIface();
63
    ASSERT_TRUE(cfg_iface);
64
    ASSERT_NO_THROW(parser.parse(cfg_iface, config_element));
65

66
67
68
    // Check it can be unparsed.
    runToElementTest<CfgIface>(config, *cfg_iface);

69
70
71
    // Open sockets according to the parsed configuration.
    SrvConfigPtr cfg = CfgMgr::instance().getStagingCfg();
    ASSERT_TRUE(cfg);
72
    ASSERT_NO_THROW(cfg->getCfgIface()->openSockets(AF_INET, 10000));
73
74
75
76
77
78

    // Only eth0 should have an open socket.
    EXPECT_TRUE(test_config.socketOpen("eth0", AF_INET));
    EXPECT_FALSE(test_config.socketOpen("eth1", AF_INET));

    // Reset configuration.
79
    cfg->getCfgIface()->closeSockets();
80
81
82
83
    CfgMgr::instance().clear();

    // Try similar configuration but this time add a wildcard interface
    // to see if sockets will open on all interfaces.
84
    config = "{ \"interfaces\": [ \"eth0\", \"*\" ] }";
85
86
    config_element = Element::fromJSON(config);

87
    cfg_iface = CfgMgr::instance().getStagingCfg()->getCfgIface();
88
    ASSERT_TRUE(cfg_iface);
89
    ASSERT_NO_THROW(parser.parse(cfg_iface, config_element));
90

91
92
    runToElementTest<CfgIface>(config, *cfg_iface);

93
    cfg = CfgMgr::instance().getStagingCfg();
94
    ASSERT_NO_THROW(cfg->getCfgIface()->openSockets(AF_INET, 10000));
95
96
97
98
99

    EXPECT_TRUE(test_config.socketOpen("eth0", AF_INET));
    EXPECT_TRUE(test_config.socketOpen("eth1", AF_INET));
}

100
101
102
103
104
105
106
107
108
// This test verifies that it is possible to select the raw socket
// use in the configuration for interfaces.
TEST_F(IfacesConfigParserTest, socketTypeRaw) {
    // Create the reference configuration, which we will compare
    // the parsed configuration to.
    CfgIface cfg_ref;

    // Configuration with a raw socket selected.
    std::string config = "{ ""\"interfaces\": [ ],"
109
        " \"dhcp-socket-type\": \"raw\" }";
110
111
112
113

    ElementPtr config_element = Element::fromJSON(config);

    // Parse the configuration.
114
115
116
    IfacesConfigParser parser(AF_INET);
    CfgIfacePtr cfg_iface = CfgMgr::instance().getStagingCfg()->getCfgIface();
    ASSERT_NO_THROW(parser.parse(cfg_iface, config_element));
117
118
119
120
121
122

    // Compare the resulting configuration with a reference
    // configuration using the raw socket.
    SrvConfigPtr cfg = CfgMgr::instance().getStagingCfg();
    ASSERT_TRUE(cfg);
    cfg_ref.useSocketType(AF_INET, CfgIface::SOCKET_RAW);
123
    EXPECT_TRUE(*cfg->getCfgIface() == cfg_ref);
124
125
126
127
128
129
130
131
132
133
}

// This test verifies that it is possible to select the datagram socket
// use in the configuration for interfaces.
TEST_F(IfacesConfigParserTest, socketTypeDatagram) {
    // Create the reference configuration, which we will compare
    // the parsed configuration to.
    CfgIface cfg_ref;

    // Configuration with a datagram socket selected.
134
    std::string config = "{ \"interfaces\": [ ],"
135
        " \"dhcp-socket-type\": \"udp\" }";
136
137
138
139

    ElementPtr config_element = Element::fromJSON(config);

    // Parse the configuration.
140
141
    IfacesConfigParser parser(AF_INET);
    CfgIfacePtr cfg_iface = CfgMgr::instance().getStagingCfg()->getCfgIface();
142
    ASSERT_TRUE(cfg_iface);
143
    ASSERT_NO_THROW(parser.parse(cfg_iface, config_element));
144

145
146
147
    // Check it can be unparsed.
    runToElementTest<CfgIface>(config, *cfg_iface);

148
149
150
151
    // Compare the resulting configuration with a reference
    // configuration using the raw socket.
    SrvConfigPtr cfg = CfgMgr::instance().getStagingCfg();
    ASSERT_TRUE(cfg);
152
    cfg_ref.useSocketType(AF_INET, CfgIface::SOCKET_UDP);
153
    ASSERT_TRUE(cfg->getCfgIface());
154
    EXPECT_TRUE(*cfg->getCfgIface() == cfg_ref);
155
156
157
158
159
}

// Test that the configuration rejects the invalid socket type.
TEST_F(IfacesConfigParserTest, socketTypeInvalid) {
    // For DHCPv4 we only accept the raw socket or datagram socket.
160
161
    IfacesConfigParser parser4(AF_INET);
    CfgIfacePtr cfg_iface = CfgMgr::instance().getStagingCfg()->getCfgIface();
162
    std::string config = "{ \"interfaces\": [ ],"
163
        "\"dhcp-socket-type\": \"default\" }";
164
    ElementPtr config_element = Element::fromJSON(config);
165
    ASSERT_THROW(parser4.parse(cfg_iface, config_element), DhcpConfigError);
166
167

    // For DHCPv6 we don't accept any socket type.
168
    IfacesConfigParser parser6(AF_INET6);
169
    config = "{ \"interfaces\": [ ],"
170
        " \"dhcp-socket-type\": \"udp\" }";
171
    config_element = Element::fromJSON(config);
172
    ASSERT_THROW(parser6.parse(cfg_iface, config_element), DhcpConfigError);
173
}
174
175

} // end of anonymous namespace