1 /*
2  * Copyright (C) 2015-2017 by Internet Systems Consortium, Inc. ("ISC")
3  *
4  * This Source Code Form is subject to the terms of the Mozilla Public
5  * License, v. 2.0. If a copy of the MPL was not distributed with this
6  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
9  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
11  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
13  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14  * PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 #include <config.h>
18 
19 #include "dhcpd.h"
20 
21 #include <atf-c.h>
22 
23 /*
24  * Test the lease queue code.  These tests will verify that we can
25  * add, find and remove leases from the lease queue code
26  *
27  * Thoughout the tests
28  * lq will be the lease queue for which we add or removing leases
29  * test_leaseX will be the leases we add or remove
30  * We only care about the sort_time in the lease structure for these
31  * tests but need to do a lease_reference in order to keep the ref
32  * count positive to avoid the omapi code trying to free the object.
33  * We can't use lease_allocate easily as we haven't set up the omapi
34  * object information in the test.
35  */
36 
37 #if defined (BINARY_LEASES)
38 #define INIT_LQ(LQ) memset(&(LQ), 0, sizeof(struct leasechain))
39 #else
40 #define INIT_LQ(LQ) lq = NULL
41 #endif
42 
43 /* Test basic leaseq functions with a single lease */
44 /*- empty, add, get, and remove */
45 ATF_TC(leaseq_basic);
ATF_TC_HEAD(leaseq_basic,tc)46 ATF_TC_HEAD(leaseq_basic, tc)
47 {
48 	atf_tc_set_md_var(tc, "descr", "Verify basic functions");
49 }
50 
ATF_TC_BODY(leaseq_basic,tc)51 ATF_TC_BODY(leaseq_basic, tc)
52 {
53 	LEASE_STRUCT lq;
54 	struct lease test_lease1, *check_lease;
55 
56 	INIT_LQ(lq);
57 
58 	memset(&test_lease1, 0, sizeof(struct lease));
59 	test_lease1.sort_time = 10;
60 	check_lease = NULL;
61 	lease_reference(&check_lease, &test_lease1, MDL);
62 
63 	/* Check that the lq is empty */
64 	if ((LEASE_NOT_EMPTY(lq)) || (LEASE_NOT_EMPTYP(&lq)))
65 		atf_tc_fail("lq not empty at start.");
66 
67 	/* And that getting the first lease is okay when queue is empty  */
68 	if ((LEASE_GET_FIRST(lq) != NULL) || (LEASE_GET_FIRSTP(&lq) != NULL))
69 		atf_tc_fail("lease not null");
70 
71 	/* Add a lease */
72 	LEASE_INSERTP(&lq, &test_lease1);
73 
74 	/* lq shouldn't be empty anymore */
75 	if (!(LEASE_NOT_EMPTY(lq)) || !(LEASE_NOT_EMPTYP(&lq)))
76 		atf_tc_fail("lq empty after insertion.");
77 
78 	/* We should have the same lease we inserted */
79 	check_lease = LEASE_GET_FIRST(lq);
80 	if (check_lease != &test_lease1)
81 		atf_tc_fail("leases don't match");
82 
83 	/* We should have the same lease we inserted */
84 	check_lease = LEASE_GET_FIRSTP(&lq);
85 	if (check_lease != &test_lease1)
86 		atf_tc_fail("leases don't match");
87 
88 	/* Check that doing a get on the last lease returns NULL */
89 	if ((LEASE_GET_NEXT(lq, check_lease) != NULL) ||
90 	    (LEASE_GET_NEXTP(&lq, check_lease) != NULL)) {
91 		atf_tc_fail("Next not null");
92 	}
93 
94 	/* Remove the lease */
95 	LEASE_REMOVEP(&lq, &test_lease1);
96 
97 	/* and verify the lease queue is empty again */
98 	if ((LEASE_NOT_EMPTY(lq)) || (LEASE_NOT_EMPTYP(&lq)))
99 		atf_tc_fail("lq not empty afer removal");
100 
101 	/* And that getting the first lease is okay when queue is empty  */
102 	if ((LEASE_GET_FIRST(lq) != NULL) || (LEASE_GET_FIRSTP(&lq) != NULL))
103 		atf_tc_fail("lease not null");
104 }
105 
106 /* Test if we can add leases to the end of the list and remove them
107  * from the end */
108 ATF_TC(leaseq_add_to_end);
ATF_TC_HEAD(leaseq_add_to_end,tc)109 ATF_TC_HEAD(leaseq_add_to_end, tc)
110 {
111 	atf_tc_set_md_var(tc, "descr", "Verify adding to end of list");
112 }
113 
ATF_TC_BODY(leaseq_add_to_end,tc)114 ATF_TC_BODY(leaseq_add_to_end, tc)
115 {
116 	LEASE_STRUCT lq;
117 	struct lease test_lease[3], *check_lease;
118 	int i;
119 
120 	INIT_LQ(lq);
121 
122 	/* create and add 3 leases */
123 	for (i = 0; i < 3; i++) {
124 		memset(&test_lease[i], 0, sizeof(struct lease));
125 		test_lease[i].sort_time = i;
126 		check_lease = NULL;
127 		lease_reference(&check_lease, &test_lease[i], MDL);
128 		LEASE_INSERTP(&lq, &test_lease[i]);
129 	}
130 
131 	/* check ordering of leases */
132 	check_lease = LEASE_GET_FIRST(lq);
133 	for (i = 0; i < 3; i++) {
134 		if (check_lease != &test_lease[i])
135 			atf_tc_fail("leases don't match, %d", i);
136 		check_lease = LEASE_GET_NEXT(lq, check_lease);
137 	}
138 	if (check_lease != NULL)
139 		atf_tc_fail("lease not null");
140 
141 	/* Remove the last lease and check the list */
142 	LEASE_REMOVEP(&lq, &test_lease[2]);
143 	check_lease = LEASE_GET_FIRST(lq);
144 	if (check_lease != &test_lease[0])
145 		atf_tc_fail("wrong lease after remove, 1");
146 	check_lease = LEASE_GET_NEXT(lq, check_lease);
147 	if (check_lease != &test_lease[1])
148 		atf_tc_fail("wrong lease after remove, 2");
149 
150 	LEASE_REMOVEP(&lq, &test_lease[1]);
151 	check_lease = LEASE_GET_FIRST(lq);
152 	if (check_lease != &test_lease[0])
153 		atf_tc_fail("wrong lease after remove, 3");
154 
155 	LEASE_REMOVEP(&lq, check_lease);
156 
157 	/* The lease queue should now be empty */
158 	if (LEASE_NOT_EMPTY(lq))
159 		atf_tc_fail("lq not empty afer removal");
160 }
161 
162 /* Test if we can add leases to the start of the list and remove them
163  * from the start */
164 ATF_TC(leaseq_add_to_start);
ATF_TC_HEAD(leaseq_add_to_start,tc)165 ATF_TC_HEAD(leaseq_add_to_start, tc)
166 {
167 	atf_tc_set_md_var(tc, "descr", "Verify adding to start of list");
168 }
169 
ATF_TC_BODY(leaseq_add_to_start,tc)170 ATF_TC_BODY(leaseq_add_to_start, tc)
171 {
172 	LEASE_STRUCT lq;
173 	struct lease test_lease[3], *check_lease;
174 	int i;
175 
176 	INIT_LQ(lq);
177 
178 	/* create 3 leases */
179 	for (i = 0; i < 3; i++) {
180 		memset(&test_lease[i], 0, sizeof(struct lease));
181 		test_lease[i].sort_time = i;
182 		check_lease = NULL;
183 		lease_reference(&check_lease, &test_lease[i], MDL);
184 	}
185 
186 	/* Add leases */
187 	LEASE_INSERTP(&lq, &test_lease[2]);
188 	LEASE_INSERTP(&lq, &test_lease[1]);
189 	LEASE_INSERTP(&lq, &test_lease[0]);
190 
191 	/* check ordering of leases */
192 	check_lease = LEASE_GET_FIRST(lq);
193 	for (i = 0; i < 3; i++) {
194 		if (check_lease != &test_lease[i])
195 			atf_tc_fail("leases don't match, %d", i);
196 		check_lease = LEASE_GET_NEXT(lq, check_lease);
197 	}
198 	if (check_lease != NULL)
199 		atf_tc_fail("lease not null");
200 
201 	/* Remove the first lease and check the next one */
202 	check_lease = LEASE_GET_FIRST(lq);
203 	LEASE_REMOVEP(&lq, check_lease);
204 	check_lease = LEASE_GET_FIRST(lq);
205 	if (check_lease != &test_lease[1])
206 		atf_tc_fail("wrong lease after remove, 1");
207 	check_lease = LEASE_GET_NEXT(lq, check_lease);
208 	if (check_lease != &test_lease[2])
209 		atf_tc_fail("wrong lease after remove, 2");
210 
211 	check_lease = LEASE_GET_FIRST(lq);
212 	LEASE_REMOVEP(&lq, check_lease);
213 	check_lease = LEASE_GET_FIRST(lq);
214 	if (check_lease != &test_lease[2])
215 		atf_tc_fail("wrong lease after remove, 3");
216 
217 	LEASE_REMOVEP(&lq, check_lease);
218 
219 	/* The lease queue should now be empty */
220 	if (LEASE_NOT_EMPTY(lq))
221 		atf_tc_fail("lq not empty afer removal");
222 }
223 
224 /* Test if we can add leases to the middle of the list and remove them
225  * from the middle */
226 ATF_TC(leaseq_add_to_middle);
ATF_TC_HEAD(leaseq_add_to_middle,tc)227 ATF_TC_HEAD(leaseq_add_to_middle, tc)
228 {
229 	atf_tc_set_md_var(tc, "descr", "Verify adding to end of list");
230 }
231 
ATF_TC_BODY(leaseq_add_to_middle,tc)232 ATF_TC_BODY(leaseq_add_to_middle, tc)
233 {
234 	LEASE_STRUCT lq;
235 	struct lease test_lease[3], *check_lease;
236 	int i;
237 
238 	INIT_LQ(lq);
239 
240 	/* create 3 leases */
241 	for (i = 0; i < 3; i++) {
242 		memset(&test_lease[i], 0, sizeof(struct lease));
243 		test_lease[i].sort_time = i;
244 		check_lease = NULL;
245 		lease_reference(&check_lease, &test_lease[i], MDL);
246 	}
247 
248 	/* Add leases */
249 	LEASE_INSERTP(&lq, &test_lease[0]);
250 	LEASE_INSERTP(&lq, &test_lease[2]);
251 	LEASE_INSERTP(&lq, &test_lease[1]);
252 
253 	/* check ordering of leases */
254 	check_lease = LEASE_GET_FIRST(lq);
255 	for (i = 0; i < 3; i++) {
256 		if (check_lease != &test_lease[i])
257 			atf_tc_fail("leases don't match, %d", i);
258 		check_lease = LEASE_GET_NEXT(lq, check_lease);
259 	}
260 	if (check_lease != NULL)
261 		atf_tc_fail("lease not null");
262 
263 	/* Remove the middle lease and check the list */
264 	LEASE_REMOVEP(&lq, &test_lease[1]);
265 	check_lease = LEASE_GET_FIRST(lq);
266 	if (check_lease != &test_lease[0])
267 		atf_tc_fail("wrong lease after remove, 1");
268 	check_lease = LEASE_GET_NEXT(lq, check_lease);
269 	if (check_lease != &test_lease[2])
270 		atf_tc_fail("wrong lease after remove, 2");
271 
272 	LEASE_REMOVEP(&lq, &test_lease[0]);
273 	check_lease = LEASE_GET_FIRST(lq);
274 	if (check_lease != &test_lease[2])
275 		atf_tc_fail("wrong lease after remove, 3");
276 
277 	LEASE_REMOVEP(&lq, check_lease);
278 
279 	/* The lease queue should now be empty */
280 	if (LEASE_NOT_EMPTY(lq))
281 		atf_tc_fail("lq not empty afer removal");
282 }
283 
284 /* Test if we can cycle the leases we add three leases then remove
285  * the first one, update it's sort time and re add it */
286 ATF_TC(leaseq_cycle);
ATF_TC_HEAD(leaseq_cycle,tc)287 ATF_TC_HEAD(leaseq_cycle, tc)
288 {
289 	atf_tc_set_md_var(tc, "descr", "Verify cycling the list");
290 }
291 
ATF_TC_BODY(leaseq_cycle,tc)292 ATF_TC_BODY(leaseq_cycle, tc)
293 {
294 	LEASE_STRUCT lq;
295 	struct lease test_lease[3], *check_lease;
296 	int i;
297 
298 	INIT_LQ(lq);
299 
300 	/* create and add 3 leases */
301 	for (i = 0; i < 3; i++) {
302 		memset(&test_lease[i], 0, sizeof(struct lease));
303 		test_lease[i].sort_time = i;
304 		check_lease = NULL;
305 		lease_reference(&check_lease, &test_lease[i], MDL);
306 		LEASE_INSERTP(&lq, &test_lease[i]);
307 	}
308 
309 	/* Remove first lease, update it and re-insert it */
310 	LEASE_REMOVEP(&lq, &test_lease[0]);
311 	test_lease[0].sort_time = 4;
312 	LEASE_INSERTP(&lq, &test_lease[0]);
313 
314 	/* check ordering of leases */
315 	check_lease = LEASE_GET_FIRST(lq);
316 	if (check_lease != &test_lease[1])
317 		atf_tc_fail("leases don't match, 1");
318 	check_lease = LEASE_GET_NEXT(lq, check_lease);
319 	if (check_lease != &test_lease[2])
320 		atf_tc_fail("leases don't match, 2");
321 	check_lease = LEASE_GET_NEXT(lq, check_lease);
322 	if (check_lease != &test_lease[0])
323 		atf_tc_fail("leases don't match, 3");
324 
325 	/* Remove first lease, update it and re-insert it */
326 	LEASE_REMOVEP(&lq, &test_lease[1]);
327 	test_lease[1].sort_time = 5;
328 	LEASE_INSERTP(&lq, &test_lease[1]);
329 
330 	/* check ordering of leases */
331 	check_lease = LEASE_GET_FIRST(lq);
332 	if (check_lease != &test_lease[2])
333 		atf_tc_fail("leases don't match, 4");
334 	check_lease = LEASE_GET_NEXT(lq, check_lease);
335 	if (check_lease != &test_lease[0])
336 		atf_tc_fail("leases don't match, 5");
337 	check_lease = LEASE_GET_NEXT(lq, check_lease);
338 	if (check_lease != &test_lease[1])
339 		atf_tc_fail("leases don't match, 6");
340 
341 	/* Remove first lease, update it and re-insert it */
342 	LEASE_REMOVEP(&lq, &test_lease[2]);
343 	test_lease[2].sort_time = 6;
344 	LEASE_INSERTP(&lq, &test_lease[2]);
345 
346 	/* check ordering of leases */
347 	check_lease = LEASE_GET_FIRST(lq);
348 	if (check_lease != &test_lease[0])
349 		atf_tc_fail("leases don't match, 7");
350 	check_lease = LEASE_GET_NEXT(lq, check_lease);
351 	if (check_lease != &test_lease[1])
352 		atf_tc_fail("leases don't match, 8");
353 	check_lease = LEASE_GET_NEXT(lq, check_lease);
354 	if (check_lease != &test_lease[2])
355 		atf_tc_fail("leases don't match, 9");
356 }
357 
358 /* Test what happens if we set the growth factor to a smallish number
359  * and add enough leases to require it to grow multiple times
360  * Mostly this is for the binary leases case but we can most of the
361  * test for both.
362  */
363 
364 ATF_TC(leaseq_long);
ATF_TC_HEAD(leaseq_long,tc)365 ATF_TC_HEAD(leaseq_long, tc)
366 {
367 	atf_tc_set_md_var(tc, "descr", "Verify a long list");
368 }
369 
ATF_TC_BODY(leaseq_long,tc)370 ATF_TC_BODY(leaseq_long, tc)
371 {
372 	LEASE_STRUCT lq;
373 	struct lease test_lease[20], *check_lease;
374 	int i;
375 
376 	INIT_LQ(lq);
377 #if defined (BINARY_LEASES)
378 	lc_init_growth(&lq, 5);
379 #endif
380 
381 	/* create and add 10 leases */
382 	for (i = 0; i < 10; i++) {
383 		memset(&test_lease[i], 0, sizeof(struct lease));
384 		test_lease[i].sort_time = i;
385 		check_lease = NULL;
386 		lease_reference(&check_lease, &test_lease[i], MDL);
387 
388 		LEASE_INSERTP(&lq, &test_lease[i]);
389 	}
390 
391 	/* check ordering of leases */
392 	check_lease = LEASE_GET_FIRST(lq);
393 	for (i = 0; i < 10; i++) {
394 		if (check_lease != &test_lease[i])
395 			atf_tc_fail("leases don't match, %d", i);
396 		check_lease = LEASE_GET_NEXT(lq, check_lease);
397 	}
398 
399 	/* Remove first 5 */
400 	for (i = 0; i < 5; i++) {
401 		LEASE_REMOVEP(&lq, &test_lease[i]);
402 	}
403 
404 	/* Add 10 more */
405 	for (i = 10; i < 20; i++) {
406 		memset(&test_lease[i], 0, sizeof(struct lease));
407 		test_lease[i].sort_time = i;
408 		check_lease = NULL;
409 		lease_reference(&check_lease, &test_lease[i], MDL);
410 
411 		LEASE_INSERTP(&lq, &test_lease[i]);
412 	}
413 
414 	/* and the first 5 */
415 	for (i = 0; i < 5; i++) {
416 		LEASE_INSERTP(&lq, &test_lease[i]);
417 	}
418 
419 	/* and check them all out */
420 	check_lease = LEASE_GET_FIRST(lq);
421 	for (i = 0; i < 20; i++) {
422 		if (check_lease != &test_lease[i])
423 			atf_tc_fail("leases don't match, %d", i);
424 		check_lease = LEASE_GET_NEXT(lq, check_lease);
425 	}
426 }
427 
428 /* Test if we can add leases that all have the same sort time
429  */
430 ATF_TC(leaseq_same_time);
ATF_TC_HEAD(leaseq_same_time,tc)431 ATF_TC_HEAD(leaseq_same_time, tc)
432 {
433 	atf_tc_set_md_var(tc, "descr", "Verify adding leases with same time");
434 }
435 
ATF_TC_BODY(leaseq_same_time,tc)436 ATF_TC_BODY(leaseq_same_time, tc)
437 {
438 	LEASE_STRUCT lq;
439 	struct lease test_lease[20], *check_lease;
440 	int i;
441 
442 	INIT_LQ(lq);
443 
444 	/* create and add 20 leases */
445 	for (i = 0; i < 20; i++) {
446 		memset(&test_lease[i], 0, sizeof(struct lease));
447 		if (i < 10)
448 			test_lease[i].sort_time = 10;
449 		else
450 			test_lease[i].sort_time = 20;
451 		check_lease = NULL;
452 		lease_reference(&check_lease, &test_lease[i], MDL);
453 		LEASE_INSERTP(&lq, &test_lease[i]);
454 	}
455 
456 #if defined (BINARY_LEASES)
457 	/* the ordering isn't well defined for either but we check
458 	 * to see what happens in the binary case.  At the start
459 	 * the leases should stay in the order they were added.
460 	 */
461 
462 	/* check ordering of leases */
463 	check_lease = LEASE_GET_FIRST(lq);
464 	for (i = 0; i < 20; i++) {
465 		if (check_lease != &test_lease[i])
466 			atf_tc_fail("leases don't match 1, %d", i);
467 		check_lease = LEASE_GET_NEXT(lq, check_lease);
468 	}
469 	if (check_lease != NULL)
470 		atf_tc_fail("lease not null");
471 #endif
472 
473 	/* Remove first 10, update their time, but still before
474 	 * the previous 10 and re add them */
475 	for (i = 0; i < 10; i++) {
476 		LEASE_REMOVEP(&lq, &test_lease[i]);
477 		test_lease[i].sort_time = 15;
478 		LEASE_INSERTP(&lq, &test_lease[i]);
479 	}
480 
481 	/* The ordering becomes random at this point so we don't
482 	 * check it.  We try to remove them all and see that
483 	 * we got to an empty queue.
484 	 */
485 	for (i = 0; i < 20; i++) {
486 		LEASE_REMOVEP(&lq, &test_lease[i]);
487 	}
488 	if (LEASE_NOT_EMPTY(lq))
489 		atf_tc_fail("queue not empty");
490 
491 }
492 
ATF_TP_ADD_TCS(tp)493 ATF_TP_ADD_TCS(tp)
494 {
495 	ATF_TP_ADD_TC(tp, leaseq_basic);
496 	ATF_TP_ADD_TC(tp, leaseq_add_to_end);
497 	ATF_TP_ADD_TC(tp, leaseq_add_to_start);
498 	ATF_TP_ADD_TC(tp, leaseq_add_to_middle);
499 	ATF_TP_ADD_TC(tp, leaseq_cycle);
500 	ATF_TP_ADD_TC(tp, leaseq_long);
501 	ATF_TP_ADD_TC(tp, leaseq_same_time);
502 	return (atf_no_error());
503 }
504