1 // Copyright (C) 2018-2021 Internet Systems Consortium, Inc. ("ISC")
2 //
3 // This Source Code Form is subject to the terms of the Mozilla Public
4 // License, v. 2.0. If a copy of the MPL was not distributed with this
5 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7 #include <config.h>
8
9 #include <yang/translator_subnet.h>
10 #include <yang/yang_models.h>
11 #include <yang/tests/sysrepo_setup.h>
12
13 #include <gtest/gtest.h>
14
15 using namespace std;
16 using namespace isc;
17 using namespace isc::data;
18 using namespace isc::yang;
19 using namespace isc::yang::test;
20 using namespace sysrepo;
21
22 namespace {
23
24 /// @brief Translator name.
25 extern char const subnet_list[] = "subnet list";
26
27 /// @brief Test fixture class for @ref TranslatorSubnets.
28 class TranslatorSubnetsTestKeaV4 :
29 public GenericTranslatorTest<subnet_list, TranslatorSubnets> {
30 public:
31
32 /// Constructor.
TranslatorSubnetsTestKeaV4()33 TranslatorSubnetsTestKeaV4() {
34 model_ = KEA_DHCP4_SERVER;
35 }
36 };
37 class TranslatorSubnetsTestKeaV6 :
38 public GenericTranslatorTest<subnet_list, TranslatorSubnets> {
39 public:
40
41 /// Constructor.
TranslatorSubnetsTestKeaV6()42 TranslatorSubnetsTestKeaV6() {
43 model_ = KEA_DHCP6_SERVER;
44 }
45 };
46 class TranslatorSubnetsTestIetfV6 :
47 public GenericTranslatorTest<subnet_list, TranslatorSubnets> {
48 public:
49
50 /// Constructor.
TranslatorSubnetsTestIetfV6()51 TranslatorSubnetsTestIetfV6() {
52 model_ = IETF_DHCPV6_SERVER;
53 }
54 };
55
56 // This test verifies that an empty subnet list can be properly
57 // translated from YANG to JSON using IETF model.
TEST_F(TranslatorSubnetsTestIetfV6,getEmptyIetf)58 TEST_F(TranslatorSubnetsTestIetfV6, getEmptyIetf) {
59 // Get the subnet list and check if it is empty.
60 const string& xpath =
61 "/ietf-dhcpv6-server:server/server-config/network-ranges";
62 ConstElementPtr subnets;
63 EXPECT_NO_THROW(subnets = t_obj_->getSubnets(xpath));
64 ASSERT_FALSE(subnets);
65 }
66
67 // This test verifies that an empty subnet list can be properly
68 // translated from YANG to JSON using Kea ad hoc model.
TEST_F(TranslatorSubnetsTestKeaV6,getEmptyKea)69 TEST_F(TranslatorSubnetsTestKeaV6, getEmptyKea) {
70 // Get the subnet list and check if it is empty.
71 const string& xpath = "/kea-dhcp6-server:config";
72 ConstElementPtr subnets;
73 EXPECT_NO_THROW(subnets = t_obj_->getSubnets(xpath));
74 ASSERT_FALSE(subnets);
75 }
76
77 // This test verifies that one subnet can be properly
78 // translated from YANG to JSON using IETF model.
TEST_F(TranslatorSubnetsTestIetfV6,getIetf)79 TEST_F(TranslatorSubnetsTestIetfV6, getIetf) {
80 // Create the subnet 2001:db8::/48 #111.
81 const string& xpath =
82 "/ietf-dhcpv6-server:server/server-config/network-ranges";
83 const string& xsub = xpath + "/network-range[network-range-id='111']";
84 S_Val v_subnet(new Val("2001:db8::/48", SR_STRING_T));
85 const string& xsubnet = xsub + "/network-prefix";
86 EXPECT_NO_THROW(sess_->set_item(xsubnet.c_str(), v_subnet));
87
88 // Get the subnet.
89 ConstElementPtr subnet;
90 EXPECT_NO_THROW(subnet = t_obj_->getSubnet(xsub));
91 ASSERT_TRUE(subnet);
92 EXPECT_EQ("{ \"id\": 111, "
93 "\"subnet\": \"2001:db8::/48\" }",
94 subnet->str());
95
96 // Get the subnet list and check if the subnet is in it.
97 ConstElementPtr subnets;
98 EXPECT_NO_THROW(subnets = t_obj_->getSubnets(xpath));
99 ASSERT_TRUE(subnets);
100 ASSERT_EQ(Element::list, subnets->getType());
101 ASSERT_EQ(1, subnets->size());
102 ASSERT_TRUE(subnets->get(0));
103 EXPECT_TRUE(subnet->equals(*subnets->get(0)));
104 }
105
106 // This test verifies that one subnet can be properly
107 // translated from YANG to JSON using Kea ad hoc model.
TEST_F(TranslatorSubnetsTestKeaV6,getKea)108 TEST_F(TranslatorSubnetsTestKeaV6, getKea) {
109 // Create the subnet 2001:db8::/48 #111.
110 const string& xpath = "/kea-dhcp6-server:config";
111 const string& xsub = xpath + "/subnet6[id='111']";
112 S_Val v_subnet(new Val("2001:db8::/48", SR_STRING_T));
113 const string& xsubnet = xsub + "/subnet";
114 EXPECT_NO_THROW(sess_->set_item(xsubnet.c_str(), v_subnet));
115
116 // Get the subnet.
117 ConstElementPtr subnet;
118 EXPECT_NO_THROW(subnet = t_obj_->getSubnet(xsub));
119 ASSERT_TRUE(subnet);
120 ElementPtr expected = Element::createMap();
121 expected->set("id", Element::create(111));
122 expected->set("subnet", Element::create(string("2001:db8::/48")));
123 EXPECT_TRUE(expected->equals(*subnet));
124
125 // Get the subnet list and check if the subnet is in it.
126 ConstElementPtr subnets;
127 EXPECT_NO_THROW(subnets = t_obj_->getSubnets(xpath));
128 ASSERT_TRUE(subnets);
129 ASSERT_EQ(Element::list, subnets->getType());
130 ASSERT_EQ(1, subnets->size());
131 EXPECT_TRUE(subnet->equals(*subnets->get(0)));
132 }
133
134 // This test verifies that one subnet with two pools can be properly
135 // translated from YANG to JSON using IETF model.
TEST_F(TranslatorSubnetsTestIetfV6,getPoolsIetf)136 TEST_F(TranslatorSubnetsTestIetfV6, getPoolsIetf) {
137 // Create the subnet 2001:db8::/48 #111.
138 const string& xpath =
139 "/ietf-dhcpv6-server:server/server-config/network-ranges";
140 const string& xsub = xpath + "/network-range[network-range-id='111']";
141 S_Val v_subnet(new Val("2001:db8::/48", SR_STRING_T));
142 const string& xsubnet = xsub + "/network-prefix";
143 EXPECT_NO_THROW(sess_->set_item(xsubnet.c_str(), v_subnet));
144
145 // Create the pool 2001:db8::1:0/112 #1.
146 const string& xpool = xsub + "/address-pools";
147 const string& prefix1 = xpool + "/address-pool[pool-id='1']/pool-prefix";
148 S_Val s_pool1(new Val("2001:db8::1:0/112"));
149 EXPECT_NO_THROW(sess_->set_item(prefix1.c_str(), s_pool1));
150
151 // Create the pool 2001:db8::2:0/112 #2.
152 const string& prefix2 = xpool + "/address-pool[pool-id='2']/pool-prefix";
153 S_Val s_pool2(new Val("2001:db8::2:0/112"));
154 EXPECT_NO_THROW(sess_->set_item(prefix2.c_str(), s_pool2));
155
156 // Get the subnet.
157 ConstElementPtr subnet;
158 EXPECT_NO_THROW(subnet = t_obj_->getSubnet(xsub));
159 ASSERT_TRUE(subnet);
160 string expected =
161 "{\n"
162 " \"id\": 111,\n"
163 " \"pools\": [\n"
164 " {\n"
165 " \"pool\": \"2001:db8::1:0/112\"\n"
166 " },\n"
167 " {\n"
168 " \"pool\": \"2001:db8::2:0/112\"\n"
169 " }\n"
170 " ],\n"
171 " \"subnet\": \"2001:db8::/48\"\n"
172 "}";
173 EXPECT_EQ(expected, prettyPrint(subnet));
174
175 // Get the subnet list and check if the subnet is in it.
176 ConstElementPtr subnets;
177 EXPECT_NO_THROW(subnets = t_obj_->getSubnets(xpath));
178 ASSERT_TRUE(subnets);
179 ASSERT_EQ(Element::list, subnets->getType());
180 ASSERT_EQ(1, subnets->size());
181 EXPECT_TRUE(subnet->equals(*subnets->get(0)));
182 }
183
184 // This test verifies that one subnet with two pools can be properly
185 // translated from YANG to JSON using Kea ad hoc model.
TEST_F(TranslatorSubnetsTestKeaV6,getPoolsKea)186 TEST_F(TranslatorSubnetsTestKeaV6, getPoolsKea) {
187 // Create the subnet 2001:db8::/48 #111.
188 const string& xpath = "/kea-dhcp6-server:config";
189 const string& xsub = xpath + "/subnet6[id='111']";
190 S_Val v_subnet(new Val("2001:db8::/48", SR_STRING_T));
191 const string& xsubnet = xsub + "/subnet";
192 EXPECT_NO_THROW(sess_->set_item(xsubnet.c_str(), v_subnet));
193
194 // Create the pool 2001:db8::1:0/112.
195 const string& prefix1 = xsub + "/pool[start-address='2001:db8::1:0']" +
196 "[end-address='2001:db8::1:ffff']/prefix";
197 S_Val s_pool1(new Val("2001:db8::1:0/112", SR_STRING_T));
198 EXPECT_NO_THROW(sess_->set_item(prefix1.c_str(), s_pool1));
199
200 // Create the pool 2001:db8::2:0/112.
201 const string& prefix2 = xsub + "/pool[start-address='2001:db8::2:0']" +
202 "[end-address='2001:db8::2:ffff']";
203 S_Val s_pool2;
204 EXPECT_NO_THROW(sess_->set_item(prefix2.c_str(), s_pool2));
205
206 // Get the subnet.
207 ConstElementPtr subnet;
208 EXPECT_NO_THROW(subnet = t_obj_->getSubnet(xsub));
209 ASSERT_TRUE(subnet);
210 string expected =
211 "{\n"
212 " \"id\": 111,\n"
213 " \"pools\": [\n"
214 " {\n"
215 " \"pool\": \"2001:db8::1:0/112\"\n"
216 " },\n"
217 " {\n"
218 " \"pool\": \"2001:db8::2:0 - 2001:db8::2:ffff\"\n"
219 " }\n"
220 " ],\n"
221 " \"subnet\": \"2001:db8::/48\"\n"
222 "}";
223 EXPECT_EQ(expected, prettyPrint(subnet));
224
225 // Get the subnet list and check if the subnet is in it.
226 ConstElementPtr subnets;
227 EXPECT_NO_THROW(subnets = t_obj_->getSubnets(xpath));
228 ASSERT_TRUE(subnets);
229 ASSERT_EQ(Element::list, subnets->getType());
230 ASSERT_EQ(1, subnets->size());
231 EXPECT_TRUE(subnet->equals(*subnets->get(0)));
232 }
233
234 // This test verifies that an empty subnet list can be properly
235 // translated from JSON to YANG using IETF model.
TEST_F(TranslatorSubnetsTestIetfV6,setEmptyIetf)236 TEST_F(TranslatorSubnetsTestIetfV6, setEmptyIetf) {
237 // Set empty list.
238 const string& xpath =
239 "/ietf-dhcpv6-server:server/server-config/network-ranges";
240 ConstElementPtr subnets = Element::createList();
241 EXPECT_NO_THROW(t_obj_->setSubnets(xpath, subnets));
242
243 // Get it back.
244 subnets.reset();
245 EXPECT_NO_THROW(subnets = t_obj_->getSubnets(xpath));
246 ASSERT_FALSE(subnets);
247 }
248
249 // This test verifies that an empty subnet list can be properly
250 // translated from JSON to YANG using Kea ad hoc model.
TEST_F(TranslatorSubnetsTestKeaV4,setEmptyKea)251 TEST_F(TranslatorSubnetsTestKeaV4, setEmptyKea) {
252 // Set empty list.
253 const string& xpath = "/kea-dhcp4-server:config";
254 ElementPtr subnets = Element::createList();
255 EXPECT_NO_THROW(t_obj_->setSubnets(xpath, subnets));
256
257 // Get it back.
258 subnets.reset();
259 EXPECT_NO_THROW(subnets = t_obj_->getSubnets(xpath));
260 ASSERT_FALSE(subnets);
261 }
262
263 // This test verifies that one subnet can be properly
264 // translated from JSON to YANG using IETF model.
TEST_F(TranslatorSubnetsTestIetfV6,setIetf)265 TEST_F(TranslatorSubnetsTestIetfV6, setIetf) {
266 // Set one subnet.
267 const string& xpath =
268 "/ietf-dhcpv6-server:server/server-config/network-ranges";
269 ElementPtr subnets = Element::createList();
270 ElementPtr subnet = Element::createMap();
271 subnet->set("subnet", Element::create(string("2001:db8::/48")));
272 subnet->set("id", Element::create(123));
273 subnets->add(subnet);
274 EXPECT_NO_THROW(t_obj_->setSubnets(xpath, subnets));
275
276 // Get it back.
277 subnets.reset();
278 EXPECT_NO_THROW(subnets = t_obj_->getSubnets(xpath));
279 ASSERT_TRUE(subnets);
280 ASSERT_EQ(Element::list, subnets->getType());
281 ASSERT_EQ(1, subnets->size());
282 EXPECT_TRUE(subnet->equals(*subnets->get(0)));
283 }
284
285 // This test verifies that one subnet can be properly
286 // translated from JSON to YANG using Kea ad hoc model.
TEST_F(TranslatorSubnetsTestKeaV4,setKea)287 TEST_F(TranslatorSubnetsTestKeaV4, setKea) {
288 // Set one subnet.
289 const string& xpath = "/kea-dhcp4-server:config";
290 ElementPtr subnets = Element::createList();
291 ElementPtr subnet = Element::createMap();
292 subnet->set("subnet", Element::create(string("10.0.1.0/24")));
293 subnet->set("id", Element::create(123));
294 subnets->add(subnet);
295 EXPECT_NO_THROW(t_obj_->setSubnets(xpath, subnets));
296
297 // Get it back.
298 subnets.reset();
299 EXPECT_NO_THROW(subnets = t_obj_->getSubnets(xpath));
300 ASSERT_TRUE(subnets);
301 ASSERT_EQ(Element::list, subnets->getType());
302 ASSERT_EQ(1, subnets->size());
303 EXPECT_TRUE(subnet->equals(*subnets->get(0)));
304
305 // Check it validates.
306 EXPECT_NO_THROW(sess_->validate());
307 }
308
309 // This test verifies that one subnet with two pools can be properly
310 // translated from JSON to YANG using IETF model.
TEST_F(TranslatorSubnetsTestIetfV6,setTwoIetf)311 TEST_F(TranslatorSubnetsTestIetfV6, setTwoIetf) {
312 // Set one subnet.
313 const string& xpath =
314 "/ietf-dhcpv6-server:server/server-config/network-ranges";
315 ElementPtr subnets = Element::createList();
316 ElementPtr subnet = Element::createMap();
317 subnet->set("subnet", Element::create(string("2001:db8::/48")));
318 subnet->set("id", Element::create(123));
319
320 // Add two pools.
321 ElementPtr pools = Element::createList();
322 ElementPtr pool1 = Element::createMap();
323 pool1->set("pool", Element::create(string("2001:db8::1:0/112")));
324 pools->add(pool1);
325 ElementPtr pool2 = Element::createMap();
326 pool2->set("pool", Element::create(string("2001:db8::2:0/112")));
327 pools->add(pool2);
328 subnet->set("pools", pools);
329
330 // Add the subnet.
331 subnets->add(subnet);
332 EXPECT_NO_THROW(t_obj_->setSubnets(xpath, subnets));
333
334 // Get it back.
335 subnets.reset();
336 EXPECT_NO_THROW(subnets = t_obj_->getSubnets(xpath));
337 ASSERT_TRUE(subnets);
338 ASSERT_EQ(Element::list, subnets->getType());
339 ASSERT_EQ(1, subnets->size());
340 EXPECT_TRUE(subnet->equals(*subnets->get(0)));
341 }
342
343 // This test verifies that one subnet with two pools can be properly
344 // translated from JSON to YANG using Kea ad hoc model.
TEST_F(TranslatorSubnetsTestKeaV4,setTwoKea)345 TEST_F(TranslatorSubnetsTestKeaV4, setTwoKea) {
346 // Set one subnet.
347 const string& xpath = "/kea-dhcp4-server:config";
348 ElementPtr subnets = Element::createList();
349 ElementPtr subnet = Element::createMap();
350 subnet->set("subnet", Element::create(string("10.0.1.0/24")));
351 subnet->set("id", Element::create(123));
352
353 // Add two pools.
354 ElementPtr pools = Element::createList();
355 ElementPtr pool1 = Element::createMap();
356 pool1->set("pool", Element::create(string("10.0.1.0/28")));
357 pools->add(pool1);
358 ElementPtr pool2 = Element::createMap();
359 pool2->set("pool", Element::create(string("10.0.1.200 - 10.0.1.222")));
360 pools->add(pool2);
361 subnet->set("pools", pools);
362
363 // Add the subnet.
364 subnets->add(subnet);
365 EXPECT_NO_THROW(t_obj_->setSubnets(xpath, subnets));
366
367 // Get it back.
368 subnets.reset();
369 EXPECT_NO_THROW(subnets = t_obj_->getSubnets(xpath));
370 ASSERT_TRUE(subnets);
371 ASSERT_EQ(Element::list, subnets->getType());
372 ASSERT_EQ(1, subnets->size());
373 EXPECT_TRUE(subnet->equals(*subnets->get(0)));
374
375 // Check it validates.
376 EXPECT_NO_THROW(sess_->validate());
377 }
378
379 } // namespace
380