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