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