Asterisk - The Open Source Telephony Project GIT-master-f36a736
parking_tests.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 2013, Digium, Inc.
5 *
6 * Jonathan Rose <jrose@digium.com>
7 *
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
13 *
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
17 */
18
19/*! \file
20 *
21 * \brief Call Parking Unit Tests
22 *
23 * \author Jonathan Rose <jrose@digium.com>
24 */
25
26#include "asterisk.h"
27
28#include "res_parking.h"
29#include "asterisk/utils.h"
30#include "asterisk/module.h"
31#include "asterisk/astobj2.h"
32#include "asterisk/test.h"
34#include "asterisk/time.h"
35#include "asterisk/causes.h"
36#include "asterisk/pbx.h"
38
39#if defined(TEST_FRAMEWORK)
40
41#define TEST_CATEGORY "/res/parking/"
42
43#define CHANNEL_TECH_NAME "ParkingTestChannel"
44
45static const struct ast_party_caller alice_callerid = {
46 .id.name.str = "Alice",
47 .id.name.valid = 1,
48 .id.number.str = "100",
49 .id.number.valid = 1,
50};
51
52static int parking_test_write(struct ast_channel *chan, struct ast_frame *frame)
53{
54 return 0;
55}
56
57static struct ast_frame *parking_test_read(struct ast_channel *chan)
58{
59 return &ast_null_frame;
60}
61
62static const struct ast_channel_tech parking_test_tech = {
64 .description = "Parking unit test technology",
65 .write = parking_test_write,
66 .read = parking_test_read,
67};
68
69/*! \brief Set ulaw format on the channel */
70static int set_test_formats(struct ast_channel *chan)
71{
72 struct ast_format_cap *caps;
73
75 if (!caps) {
76 return -1;
77 }
78
85 ao2_ref(caps, -1);
86
87 return 0;
88}
89
90/*! \brief Create a \ref test_cdr_chan_tech for Alice */
91static struct ast_channel *create_alice_channel(void)
92{
94 "100", "Alice", "100", "100", "default", NULL, NULL, 0,
95 CHANNEL_TECH_NAME "/Alice");
96
97 if (!alice) {
98 return NULL;
99 }
100
101 if (set_test_formats(alice)) {
102 ast_channel_unlock(alice);
103 ast_channel_release(alice);
104 return NULL;
105 }
106
107 ast_channel_tech_set(alice, &parking_test_tech);
108
109 ast_channel_set_caller(alice, &alice_callerid, NULL);
110
111 ast_channel_unlock(alice);
112
113 return alice;
114}
115
116/*! \brief Hang up a test channel safely */
117static struct ast_channel *hangup_channel(struct ast_channel *chan, int hangup_cause)
118{
119 ast_channel_hangupcause_set(chan, hangup_cause);
120 ast_hangup(chan);
121 return NULL;
122}
123
124static void safe_channel_release(struct ast_channel *chan)
125{
126 if (!chan) {
127 return;
128 }
130}
131
132static void do_sleep(struct timespec *to_sleep)
133{
134 while ((nanosleep(to_sleep, to_sleep) == -1) && (errno == EINTR)) {
135 }
136}
137
138#define TEST_LOT_NAME "unit_tests_res_parking_test_lot"
139
140static struct parking_lot *generate_test_parking_lot(const char *name, int low_space, int high_space, const char *park_exten, const char *park_context, struct ast_test *test)
141{
142 RAII_VAR(struct parking_lot_cfg *, test_cfg, NULL, ao2_cleanup);
143 struct parking_lot *test_lot;
144
145 test_cfg = parking_lot_cfg_create(name);
146 if (!test_cfg) {
147 return NULL;
148 }
149
150 test_cfg->parking_start = low_space;
151 test_cfg->parking_stop = high_space;
152 test_cfg->parkingtime = 10;
153 test_cfg->comebackdialtime = 10;
154 test_cfg->parkfindnext = 1;
155 test_cfg->parkext_exclusive = 1;
156 ast_string_field_set(test_cfg, parkext, park_exten);
157 ast_string_field_set(test_cfg, parking_con, park_context);
158 ast_string_field_set(test_cfg, comebackcontext, "unit_test_res_parking_create_lot_comeback");
159
160 if (parking_lot_cfg_create_extensions(test_cfg)) {
161 ast_test_status_update(test, "Extensions for parking lot '%s' could not be registered. Extension Creation failed.\n", name);
162 return NULL;
163 }
164
165 test_lot = parking_lot_build_or_update(test_cfg, 1);
166 if (!test_lot) {
167 return NULL;
168 }
169
170 return test_lot;
171}
172
173static int dispose_test_lot(struct parking_lot *test_lot, int expect_destruction)
174{
175 RAII_VAR(struct parking_lot *, found_lot, NULL, ao2_cleanup);
176
177 test_lot->mode = PARKINGLOT_DISABLED;
179
180 found_lot = parking_lot_find_by_name(test_lot->name);
181
182 if ((expect_destruction && !found_lot) || (!expect_destruction && found_lot)) {
183 return 0;
184 }
185
186 return -1;
187}
188
189AST_TEST_DEFINE(create_lot)
190{
191 RAII_VAR(struct parking_lot *, test_lot, NULL, ao2_cleanup);
192 RAII_VAR(struct parking_lot *, found_copy, NULL, ao2_cleanup);
193
194 switch (cmd) {
195 case TEST_INIT:
196 info->name = "create_lot";
197 info->category = TEST_CATEGORY;
198 info->summary = "Parking lot creation";
199 info->description =
200 "Creates a parking lot and then disposes of it.";
201 return AST_TEST_NOT_RUN;
202 case TEST_EXECUTE:
203 break;
204 }
205
206 ast_test_status_update(test, "Creating test parking lot '%s'\n", TEST_LOT_NAME);
207
208 test_lot = generate_test_parking_lot(TEST_LOT_NAME, 701, 703, NULL, "unit_test_res_parking_create_lot_con", test);
209 if (!test_lot) {
210 ast_test_status_update(test, "Failed to create test parking lot. Test Failed\n");
211 return AST_TEST_FAIL;
212 }
213
214 ast_test_status_update(test, "Successfully created parking lot. Retrieving test parking lot from container.\n");
215
216 found_copy = parking_lot_find_by_name(TEST_LOT_NAME);
217 if (!found_copy) {
218 ast_test_status_update(test, "Failed to find parking lot in the parking lot container. Test failed.\n");
219 dispose_test_lot(test_lot, 1);
220 return AST_TEST_FAIL;
221 }
222
223 ast_test_status_update(test, "Successfully retrieved parking lot. Removing test parking lot from container.\n");
224
225 if (dispose_test_lot(found_copy, 1)) {
226 ast_test_status_update(test, "Found parking lot in container after attempted removal. Test failed.\n");
227 }
228
229 ast_test_status_update(test, "Parking lot was successfully removed from the container. Test complete.\n");
230
231 return AST_TEST_PASS;
232}
233
234AST_TEST_DEFINE(park_call)
235{
236 RAII_VAR(struct parking_lot *, test_lot, NULL, ao2_cleanup);
237 RAII_VAR(struct ast_channel *, chan_alice, NULL, safe_channel_release);
239
240 struct timespec to_sleep = {1, 0};
241
242 switch (cmd) {
243 case TEST_INIT:
244 info->name = "park_channel";
245 info->category = TEST_CATEGORY;
246 info->summary = "Park a Channel";
247 info->description =
248 "Creates a parking lot, parks a channel in it, then removes it from the parking lot bridge.";
249 return AST_TEST_NOT_RUN;
250 case TEST_EXECUTE:
251 break;
252 }
253
254 ast_test_status_update(test, "Creating test parking lot '%s'\n", TEST_LOT_NAME);
255
256 test_lot = generate_test_parking_lot(TEST_LOT_NAME, 701, 703, NULL, "unit_test_res_parking_create_lot_con", test);
257 if (!test_lot) {
258 ast_test_status_update(test, "Failed to create test parking lot. Test failed.\n");
259 return AST_TEST_FAIL;
260 }
261
262 chan_alice = create_alice_channel();
263 if (!chan_alice) {
264 ast_test_status_update(test, "Failed to create test channel to park. Test failed.\n");
265 dispose_test_lot(test_lot, 1);
266 return AST_TEST_FAIL;
267 }
268
270 pbx_builtin_setvar_helper(chan_alice, "BLINDTRANSFER", ast_channel_name(chan_alice));
271
272 parking_bridge = park_application_setup(chan_alice, chan_alice, TEST_LOT_NAME, NULL);
273 if (!parking_bridge) {
274 ast_test_status_update(test, "Failed to get the parking bridge for '%s'. Test failed.\n", TEST_LOT_NAME);
275 dispose_test_lot(test_lot, 1);
276 return AST_TEST_FAIL;
277 }
278
279 if (ast_bridge_impart(parking_bridge, chan_alice, NULL, NULL,
281 ast_test_status_update(test, "Failed to impart alice into parking lot. Test failed.\n");
282 dispose_test_lot(test_lot, 1);
283 return AST_TEST_FAIL;
284 }
285
287
288 ast_bridge_depart(chan_alice);
289
290 chan_alice = hangup_channel(chan_alice, AST_CAUSE_NORMAL);
291
292 if (dispose_test_lot(test_lot, 1)) {
293 ast_test_status_update(test, "Found parking lot in container after attempted removal. Test failed.\n");
294 return AST_TEST_FAIL;
295 }
296
297 return AST_TEST_PASS;
298
299}
300
301static int parked_users_match(const struct parked_user *actual, const struct parked_user *expected, struct ast_test *test)
302{
303 if (expected->parking_space != actual->parking_space) {
304 ast_test_status_update(test, "parking_space expected: %d - got: %d\n", expected->parking_space, actual->parking_space);
305 return 0;
306 }
307
308 if (strcmp(expected->parker_dial_string, actual->parker_dial_string)) {
309 ast_test_status_update(test, "parker_dial_string expected: %s - got: %s\n", expected->parker_dial_string, actual->parker_dial_string);
310 return 0;
311 }
312
313 if (expected->time_limit != actual->time_limit) {
314 ast_test_status_update(test, "time_limit expected: %u - got: %u\n", expected->time_limit, actual->time_limit);
315 return 0;
316 }
317
318 if (expected->resolution != actual->resolution) {
319 ast_test_status_update(test, "resolution expected: %u - got: %u\n", expected->resolution, actual->resolution);
320 return 0;
321 }
322
323 return 1;
324}
325
326static int parking_lot_cfgs_match(const struct parking_lot_cfg *actual, const struct parking_lot_cfg *expected, struct ast_test *test)
327{
328 if (expected->parking_start != actual->parking_start) {
329 ast_test_status_update(test, "parking_start expected: %d - got: %d\n", expected->parking_start, actual->parking_start);
330 return 0;
331 }
332
333 if (expected->parking_stop != actual->parking_stop) {
334 ast_test_status_update(test, "parking_stop expected: %d - got: %d\n", expected->parking_stop, actual->parking_stop);
335 return 0;
336 }
337
338 if (expected->parkingtime != actual->parkingtime) {
339 ast_test_status_update(test, "parkingtime expected: %u - got: %u\n", expected->parkingtime, actual->parkingtime);
340 return 0;
341 }
342
343 if (expected->comebackdialtime != actual->comebackdialtime) {
344 ast_test_status_update(test, "comebackdialtime expected: %u - got: %u\n", expected->comebackdialtime, actual->comebackdialtime);
345 return 0;
346 }
347
348 if (expected->parkfindnext != actual->parkfindnext) {
349 ast_test_status_update(test, "parkfindnext expected: %u - got: %u\n", expected->parkfindnext, actual->parkfindnext);
350 return 0;
351 }
352
353 if (expected->parkext_exclusive != actual->parkext_exclusive) {
354 ast_test_status_update(test, "parkext_exclusive expected: %u - got: %u\n", expected->parkext_exclusive, actual->parkext_exclusive);
355 return 0;
356 }
357
358 if (strcmp(expected->parkext, actual->parkext)) {
359 ast_test_status_update(test, "parkext expected: %s - got: %s\n", expected->parkext, actual->parkext);
360 return 0;
361 }
362
363 if (strcmp(expected->parking_con, actual->parking_con)) {
364 ast_test_status_update(test, "parking_con expected: %s - got: %s\n", expected->parking_con, actual->parking_con);
365 return 0;
366 }
367
368 if (strcmp(expected->comebackcontext, actual->comebackcontext)) {
369 ast_test_status_update(test, "comebackcontext expected: %s - got: %s\n", expected->comebackcontext, actual->comebackcontext);
370 return 0;
371 }
372
373 return 1;
374}
375
376AST_TEST_DEFINE(retrieve_call)
377{
378 RAII_VAR(struct parking_lot *, test_lot, NULL, ao2_cleanup);
379 RAII_VAR(struct ast_channel *, chan_alice, NULL, safe_channel_release);
380 RAII_VAR(struct ast_bridge *, parking_bridge, NULL, ao2_cleanup);
381 RAII_VAR(struct parked_user *, retrieved_user, NULL, ao2_cleanup);
382
383 struct timespec to_sleep = {1, 0};
384 int failure = 0;
385
386 static const struct parked_user expected_user = {
387 .parking_space = 701,
388 .parker_dial_string = "ParkingTestChannel/Alice",
389 .time_limit = 10,
390 .resolution = PARK_ANSWERED,
391 };
392
393 switch (cmd) {
394 case TEST_INIT:
395 info->name = "park_retrieve";
396 info->category = TEST_CATEGORY;
397 info->summary = "Retrieve a parked channel";
398 info->description =
399 "Creates a parking lot, parks a channel in it, then removes it from the parking lot bridge.";
400 return AST_TEST_NOT_RUN;
401 case TEST_EXECUTE:
402 break;
403 }
404
405 ast_test_status_update(test, "Creating test parking lot '%s'\n", TEST_LOT_NAME);
406
407 test_lot = generate_test_parking_lot(TEST_LOT_NAME, 701, 703, NULL, "unit_test_res_parking_create_lot_con", test);
408 if (!test_lot) {
409 ast_test_status_update(test, "Failed to create test parking lot. Test failed.\n");
410 return AST_TEST_FAIL;
411 }
412
413 chan_alice = create_alice_channel();
414 if (!chan_alice) {
415 ast_test_status_update(test, "Failed to create test channel to park. Test failed.\n");
416 dispose_test_lot(test_lot, 1);
417 return AST_TEST_FAIL;
418 }
419
421 pbx_builtin_setvar_helper(chan_alice, "BLINDTRANSFER", ast_channel_name(chan_alice));
422
423 parking_bridge = park_application_setup(chan_alice, chan_alice, TEST_LOT_NAME, NULL);
424 if (!parking_bridge) {
425 ast_test_status_update(test, "Failed to get the parking bridge for '%s'. Test failed.\n", TEST_LOT_NAME);
426 dispose_test_lot(test_lot, 1);
427 return AST_TEST_FAIL;
428 }
429
430 if (ast_bridge_impart(parking_bridge, chan_alice, NULL, NULL,
432 ast_test_status_update(test, "Failed to impart alice into parking lot. Test failed.\n");
433 dispose_test_lot(test_lot, 1);
434 return AST_TEST_FAIL;
435 }
436
438
439 retrieved_user = parking_lot_retrieve_parked_user(test_lot, 701);
440 if (!retrieved_user) {
441 ast_test_status_update(test, "Failed to retrieve the parked user from the expected parking space. Test failed.\n");
442 failure = 1;
443 goto test_cleanup;
444 }
445
446 ast_test_status_update(test, "Successfully retrieved parked user from the parking lot. Validating user data.\n");
447
448 if (!parked_users_match(retrieved_user, &expected_user, test)) {
449 ast_test_status_update(test, "Parked user validation failed\n");
450 failure = 1;
451 goto test_cleanup;
452 }
453
454 if (retrieved_user->chan != chan_alice) {
455 ast_test_status_update(test, "The retrieved parked channel didn't match the expected channel. Test failed.\n");
456 failure = 1;
457 goto test_cleanup;
458 }
459
460test_cleanup:
461 ast_bridge_depart(chan_alice);
462 chan_alice = hangup_channel(chan_alice, AST_CAUSE_NORMAL);
463 if (dispose_test_lot(test_lot, 1)) {
464 ast_test_status_update(test, "Found parking lot in container after attempted removal. Test failed.\n");
465 failure = 1;
466 }
467
468 return failure ? AST_TEST_FAIL : AST_TEST_PASS;
469}
470
471static int check_retrieve_call_extensions(struct ast_test *test, int expected)
472{
473 struct ast_exten *check;
474 struct pbx_find_info find_info = { .stacklen = 0 }; /* the rest is reset in pbx_find_extension */
475 int extens;
476 char search_buffer[4];
477
478 /* Check the parking extensions */
479 check = pbx_find_extension(NULL, NULL, &find_info, "unit_test_res_parking_create_lot_con", "700", 1, NULL, NULL, E_MATCH);
480
481 if (check ? !expected : expected) {
482 /* extension isn't present when it should be or is present when it shouldn't be. Automatic failure. */
483 ast_test_status_update(test, "An extension '700' was %s when it %s have been. Test failed.\n",
484 expected ? "not present" : "present",
485 expected ? "should" : "should not");
486 return -1;
487 } else if (check && expected) {
488 if (strcmp(ast_get_extension_app(check), "Park")) {
489 ast_test_status_update(test, "An extension '700' has the wrong application associated with it. Got '%s' expected 'Park'.\n",
490 ast_get_extension_app(check));
491 return -1;
492 }
493 }
494
495
496 /* Check the parking space extensions 701-703 */
497 for (extens = 701; extens <= 703; extens++) {
498 sprintf(search_buffer, "%d", extens);
499 find_info.stacklen = 0; /* reset for pbx_find_extension */
500
501 check = pbx_find_extension(NULL, NULL, &find_info, "unit_test_res_parking_create_lot_con", search_buffer, 1, NULL, NULL, E_MATCH);
502
503 if (check ? !expected : expected) {
504 /* extension isn't present when it should be or is present when it shouldn't be. Automatic failure. */
505 ast_test_status_update(test, "An extension '%s' was %s when it %s have been. Test failed.\n",
506 search_buffer,
507 expected ? "not present" : "present",
508 expected ? "should" : "should not");
509 return -1;
510 } else if (check && expected) {
511 if (strcmp(ast_get_extension_app(check), "ParkedCall")) {
512 ast_test_status_update(test, "An extension '%s' has the wrong application associated with it. Got '%s', expected 'ParkedCall'.\n",
513 search_buffer,
514 ast_get_extension_app(check));
515 return -1;
516 }
517 }
518 }
519
520 return 0;
521
522}
523
524AST_TEST_DEFINE(park_extensions)
525{
526 RAII_VAR(struct parking_lot *, test_lot, NULL, ao2_cleanup);
527
528 switch (cmd) {
529 case TEST_INIT:
530 info->name = "park_extensions";
531 info->category = TEST_CATEGORY;
532 info->summary = "Parking lot extension creation tests";
533 info->description =
534 "Creates parking lots and checks that they registered the expected extensions, then removes them.";
535 return AST_TEST_NOT_RUN;
536 case TEST_EXECUTE:
537 break;
538 }
539
540 test_lot = generate_test_parking_lot(TEST_LOT_NAME, 701, 703, "700", "unit_test_res_parking_create_lot_con", test);
541 if (!test_lot) {
542 ast_test_status_update(test, "Failed to create test parking lot. Test Failed.\n");
543 return AST_TEST_FAIL;
544 }
545
546 if (check_retrieve_call_extensions(test, 1)) {
547 dispose_test_lot(test_lot, 1);
548 return AST_TEST_FAIL;
549 }
550
551 ast_test_status_update(test, "Extensions for the test parking lot were verified. Cleaning up and verifying their removal.\n");
552
553 if (dispose_test_lot(test_lot, 1)) {
554 ast_test_status_update(test, "Found parking lot in container after attempted removal. Test failed.\n");
555 return AST_TEST_FAIL;
556 }
557 ao2_cleanup(test_lot);
558 test_lot = NULL;
559
560 if (check_retrieve_call_extensions(test, 0)) {
561 ast_log(LOG_ERROR, "Test 'park_extensions' failed to clean up after itself properly.\n");
562 return AST_TEST_FAIL;
563 }
564
565 ast_test_status_update(test, "Extensions for the test parking lot verified as removed. Test completed successfully.\n");
566
567 return AST_TEST_PASS;
568}
569
570AST_TEST_DEFINE(extension_conflicts)
571{
572 RAII_VAR(struct parking_lot *, base_lot, NULL, ao2_cleanup);
573 RAII_VAR(struct parking_lot *, expect_fail1, NULL, ao2_cleanup); /* Failure due to overlapping parkexten */
574 RAII_VAR(struct parking_lot *, expect_fail2, NULL, ao2_cleanup); /* Failure due to overlapping spaces */
575 RAII_VAR(struct parking_lot *, expect_fail3, NULL, ao2_cleanup); /* parkexten overlaps parking spaces */
576 RAII_VAR(struct parking_lot *, expect_fail4, NULL, ao2_cleanup); /* parking spaces overlap parkexten */
577 RAII_VAR(struct parking_lot *, expect_success1, NULL, ao2_cleanup); /* Success due to being in a different context */
578 RAII_VAR(struct parking_lot *, expect_success2, NULL, ao2_cleanup); /* Success due to not having overlapping extensions */
579 RAII_VAR(struct parking_lot *, expect_success3, NULL, ao2_cleanup); /* Range of parking spaces differs by one above */
580 RAII_VAR(struct parking_lot *, expect_success4, NULL, ao2_cleanup); /* Range of parking spaces differs by one below */
581 char *cur_lot_name;
582
583 int failed = 0;
584
585 switch (cmd) {
586 case TEST_INIT:
587 info->name = "extension_conflicts";
588 info->category = TEST_CATEGORY;
589 info->summary = "Tests the addition of parking lot extensions to make sure conflicts are detected";
590 info->description =
591 "Creates parking lots with overlapping extensions to test for conflicts";
592 return AST_TEST_NOT_RUN;
593 case TEST_EXECUTE:
594 break;
595 }
596
597 ast_test_status_update(test, "Creating the base lot. This should pass.\n");
598 base_lot = generate_test_parking_lot(TEST_LOT_NAME, 701, 703, "700", "unit_test_res_parking_create_lot_con", test);
599
600 if (!base_lot) {
601 ast_test_status_update(test, "Failed to create the base parking lot. Test failed.\n");
602 failed = 1;
603 goto cleanup;
604 }
605
606 cur_lot_name = "unit_tests_res_parking_test_lot_fail1";
607 ast_test_status_update(test, "Creating a test lot which will overlap.\n");
608 expect_fail1 = generate_test_parking_lot(cur_lot_name,
609 801, 803, "700", "unit_test_res_parking_create_lot_con", /* The parkexten overlaps the parkexten of the base */
610 test);
611
612 if (expect_fail1) {
613 ast_test_status_update(test, "%s was successfully created when it was expected to fail. Test failed.\n", cur_lot_name);
614 failed = 1;
615 goto cleanup;
616 }
617
618 cur_lot_name = "unit_tests_res_parking_test_lot_fail2";
619 expect_fail2 = generate_test_parking_lot(cur_lot_name,
620 702, 705, "800", "unit_test_res_parking_create_lot_con", /* The range overlaps the range of the base */
621 test);
622 if (expect_fail2) {
623 ast_test_status_update(test, "%s was successfully created when it was expected to fail. Test failed.\n", cur_lot_name);
624 failed = 1;
625 goto cleanup;
626 }
627
628 cur_lot_name = "unit_tests_res_parking_test_lot_fail3";
629 expect_fail3 = generate_test_parking_lot(cur_lot_name,
630 698, 700, "testfail3", "unit_test_res_parking_create_lot_con", /* The range overlaps the parkexten of the base */
631 test);
632 if (expect_fail3) {
633 ast_test_status_update(test, "%s was successfully created when it was expected to fail. Test failed.\n", cur_lot_name);
634 failed = 1;
635 goto cleanup;
636 }
637
638 cur_lot_name = "unit_tests_res_parking_test_lot_fail4";
639 expect_fail4 = generate_test_parking_lot(cur_lot_name,
640 704, 706, "703", "unit_test_res_parking_create_lot_con", /* The parkexten overlaps the range of the base */
641 test);
642 if (expect_fail4) {
643 ast_test_status_update(test, "%s was successfully created when it was expected to fail. Test failed.\n", cur_lot_name);
644 failed = 1;
645 goto cleanup;
646 }
647
648 cur_lot_name = "unit_tests_res_parking_test_lot_success1";
649 expect_success1 = generate_test_parking_lot(cur_lot_name,
650 701, 703, "700", "unit_test_res_parking_create_lot_con_2", /* no overlap due to different context */
651 test);
652 if (!expect_success1) {
653 ast_test_status_update(test, "%s failed to be created. Success was expected. Test failed.\n", cur_lot_name);
654 failed = 1;
655 goto cleanup;
656 }
657
658 cur_lot_name = "unit_tests_res_parking_test_lot_success2";
659 expect_success2 = generate_test_parking_lot(cur_lot_name,
660 601, 605, "600", "unit_test_res_parking_create_lot_con", /* no overlap due to different extensions and ranges */
661 test);
662 if (!expect_success2) {
663 ast_test_status_update(test, "%s failed to be created. Success was expected. Test failed.\n", cur_lot_name);
664 failed = 1;
665 goto cleanup;
666 }
667
668 cur_lot_name = "unit_tests_res_parking_test_lot_success3";
669 expect_success3 = generate_test_parking_lot(cur_lot_name,
670 704, 706, "testsuccess3", "unit_test_res_parking_create_lot_con", /* no overlap because the parking spaces start 1 above existing ranges */
671 test);
672 if (!expect_success3) {
673 ast_test_status_update(test, "%s failed to be created. Success was expected. Test failed.\n", cur_lot_name);
674 failed = 1;
675 goto cleanup;
676 }
677
678 cur_lot_name = "unit_tests_res_parking_test_lot_success4";
679 expect_success4 = generate_test_parking_lot(cur_lot_name,
680 697, 699, "testsuccess4", "unit_test_res_parking_create_lot_con", /* no overlap because the parking spaces end 1 below existing ranges */
681 test);
682 if (!expect_success4) {
683 failed = 1;
684 goto cleanup;
685 }
686
687cleanup:
688 if (base_lot && dispose_test_lot(base_lot, 1)) {
689 ast_test_status_update(test, "Found base parking lot in container after attempted removal. Test failed.\n");
690 failed = 1;
691 }
692
693 if (expect_fail1) {
694 dispose_test_lot(expect_fail1, 1);
695 failed = 1;
696 }
697
698 if (expect_fail2) {
699 dispose_test_lot(expect_fail2, 1);
700 failed = 1;
701 }
702
703 if (expect_fail3) {
704 dispose_test_lot(expect_fail3, 1);
705 failed = 1;
706 }
707
708 if (expect_fail4) {
709 dispose_test_lot(expect_fail4, 1);
710 failed = 1;
711 }
712
713 if (expect_success1 && dispose_test_lot(expect_success1, 1)) {
714 ast_test_status_update(test, "Found expect_success1 parking lot in container after attempted removal. Test failed.\n");
715 failed = 1;
716 }
717
718 if (expect_success2 && dispose_test_lot(expect_success2, 1)) {
719 ast_test_status_update(test, "Found expect_success2 parking lot in container after attempted removal. Test failed.\n");
720 failed = 1;
721 }
722
723 if (expect_success3 && dispose_test_lot(expect_success3, 1)) {
724 ast_test_status_update(test, "Found expect_success3 parking lot in container after attempted removal. Test failed.\n");
725 failed = 1;
726 }
727
728 if (expect_success4 && dispose_test_lot(expect_success4, 1)) {
729 ast_test_status_update(test, "Found expect_success4 parking lot in container after attempted removal. Test failed.\n");
730 }
731
732 return failed ? AST_TEST_FAIL : AST_TEST_PASS;
733}
734
735AST_TEST_DEFINE(dynamic_parking_variables)
736{
737 RAII_VAR(struct parking_lot *, template_lot, NULL, ao2_cleanup);
738 RAII_VAR(struct parking_lot *, dynamic_lot, NULL, ao2_cleanup);
739 RAII_VAR(struct ast_channel *, chan_alice, NULL, safe_channel_release);
740 RAII_VAR(struct parking_lot_cfg *, expected_cfg, NULL, ao2_cleanup);
741
742 int failed = 0;
743
744 switch (cmd) {
745 case TEST_INIT:
746 info->name = "dynamic_parking_variables";
747 info->category = TEST_CATEGORY;
748 info->summary = "Tests whether dynamic parking lot creation respects channel variables";
749 info->description =
750 "Creates a template parking lot, creates a channel, sets dynamic parking variables, and then creates a parking lot for that channel";
751 return AST_TEST_NOT_RUN;
752 case TEST_EXECUTE:
753 break;
754 }
755
756 ast_test_status_update(test, "Creating expected configuration for dynamic parking lot\n");
757
758 expected_cfg = parking_lot_cfg_create("unit_tests_res_parking_test_lot_dynamic");
759
760 if (!expected_cfg) {
761 ast_test_status_update(test, "Failed to create expected configuration. Test failed.\n");
762 return AST_TEST_FAIL;
763 }
764
765 expected_cfg->parking_start = 751;
766 expected_cfg->parking_stop = 760;
767 expected_cfg->parkingtime = 10;
768 expected_cfg->comebackdialtime = 10;
769 expected_cfg->parkfindnext = 1;
770 expected_cfg->parkext_exclusive = 1;
771 ast_string_field_set(expected_cfg, parkext, "750");
772 ast_string_field_set(expected_cfg, parking_con, "unit_test_res_parking_create_lot_dynamic");
773 ast_string_field_set(expected_cfg, comebackcontext, "unit_test_res_parking_create_lot_comeback");
774
775 ast_test_status_update(test, "Creating template lot\n");
776
777 template_lot = generate_test_parking_lot(TEST_LOT_NAME, 701, 703, "700", "unit_test_res_parking_create_lot_con", test);
778
779 if (!template_lot) {
780 ast_test_status_update(test, "Failed to generate template lot. Test failed.\n");
781 return AST_TEST_FAIL;
782 }
783
784 ast_test_status_update(test, "Creating Alice channel to test dynamic parking lot creation.\n");
785
786 chan_alice = create_alice_channel();
787
788 if (!chan_alice) {
789 ast_test_status_update(test, "Failed to create Alice channel. Test failed.\n");
790 failed = 1;
791 goto cleanup;
792 }
793
794 ast_test_status_update(test, "Setting Dynamic Parking channel variables on Alice.\n");
795
796 pbx_builtin_setvar_helper(chan_alice, "PARKINGDYNAMIC", TEST_LOT_NAME);
797 pbx_builtin_setvar_helper(chan_alice, "PARKINGLOT", "unit_test_res_parking_create_lot_dynamic");
798 pbx_builtin_setvar_helper(chan_alice, "PARKINGDYNCONTEXT", "unit_test_res_parking_create_lot_dynamic");
799 pbx_builtin_setvar_helper(chan_alice, "PARKINGDYNEXTEN", "750");
800 pbx_builtin_setvar_helper(chan_alice, "PARKINGDYNPOS", "751-760");
801
802 ast_test_status_update(test, "Generating dynamic parking lot based on Alice's channel variables.\n");
803
804 dynamic_lot = parking_create_dynamic_lot_forced("unit_tests_res_parking_test_lot_dynamic", chan_alice);
805
806 if (!dynamic_lot) {
807 ast_test_status_update(test, "Failed to create dynamic parking lot. Test failed.\n");
808 failed = 1;
809 goto cleanup;
810 }
811
812 /* Check stats */
813 if (!parking_lot_cfgs_match(dynamic_lot->cfg, expected_cfg, test)) {
814 ast_test_status_update(test, "Dynamic parking lot configuration did not match Expectations.\n");
815 failed = 1;
816 goto cleanup;
817 }
818
819 ast_test_status_update(test, "Dynamic parking lot created successfully and matches expectations. Test passed.\n");
820
821cleanup:
822 if (template_lot && dispose_test_lot(template_lot, 1)) {
823 ast_test_status_update(test, "Found template parking lot in container after attempted removal. Test failed.\n");
824 failed = 1;
825 }
826
827 if (dynamic_lot && dispose_test_lot(dynamic_lot, 1)) {
828 ast_test_status_update(test, "Found dynamic parking lot in container after attempted removal. Test failed.\n");
829 failed = 1;
830 }
831
832 return failed ? AST_TEST_FAIL : AST_TEST_PASS;
833}
834
835#endif /* TEST_FRAMEWORK */
836
837
839{
840/* NOOP without test framework */
841#if defined(TEST_FRAMEWORK)
842 AST_TEST_UNREGISTER(create_lot);
843 AST_TEST_UNREGISTER(park_call);
844 AST_TEST_UNREGISTER(retrieve_call);
845 AST_TEST_UNREGISTER(park_extensions);
846 AST_TEST_UNREGISTER(extension_conflicts);
847 AST_TEST_UNREGISTER(dynamic_parking_variables);
848#endif
849}
850
852{
853 int res = 0;
854
855/* NOOP without test framework */
856#if defined(TEST_FRAMEWORK)
857 res |= AST_TEST_REGISTER(create_lot);
858 res |= AST_TEST_REGISTER(park_call);
859 res |= AST_TEST_REGISTER(retrieve_call);
860 res |= AST_TEST_REGISTER(park_extensions);
861 res |= AST_TEST_REGISTER(extension_conflicts);
862 res |= AST_TEST_REGISTER(dynamic_parking_variables);
863#endif
864
865 return res;
866}
int extens
Definition: ael_main.c:93
Asterisk main include file. File version handling, generic pbx functions.
#define ast_log
Definition: astobj2.c:42
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
int ast_bridge_depart(struct ast_channel *chan)
Depart a channel from a bridge.
Definition: bridge.c:1906
int ast_bridge_impart(struct ast_bridge *bridge, struct ast_channel *chan, struct ast_channel *swap, struct ast_bridge_features *features, enum ast_bridge_impart_flags flags) attribute_warn_unused_result
Impart a channel to a bridge (non-blocking)
Definition: bridge.c:1878
@ AST_BRIDGE_IMPART_CHAN_DEPARTABLE
Definition: bridge.h:588
Internal Asterisk hangup causes.
#define AST_CAUSE_NORMAL
Definition: causes.h:151
const char * ast_channel_name(const struct ast_channel *chan)
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition: channel.c:2560
void ast_channel_set_caller(struct ast_channel *chan, const struct ast_party_caller *caller, const struct ast_set_party_caller *update)
Set the caller id information in the Asterisk channel.
Definition: channel.c:7381
#define ast_channel_alloc(needqueue, state, cid_num, cid_name, acctcode, exten, context, assignedids, requestor, amaflag,...)
Create a channel structure.
Definition: channel.h:1299
void ast_channel_nativeformats_set(struct ast_channel *chan, struct ast_format_cap *value)
void ast_channel_set_rawreadformat(struct ast_channel *chan, struct ast_format *format)
void ast_channel_set_rawwriteformat(struct ast_channel *chan, struct ast_format *format)
struct ast_channel * ast_channel_release(struct ast_channel *chan)
Unlink and release reference to a channel.
Definition: channel.c:1603
void ast_channel_set_readformat(struct ast_channel *chan, struct ast_format *format)
void ast_channel_state_set(struct ast_channel *chan, enum ast_channel_state)
void ast_channel_hangupcause_set(struct ast_channel *chan, int value)
void ast_channel_tech_set(struct ast_channel *chan, const struct ast_channel_tech *value)
#define ast_channel_unlock(chan)
Definition: channel.h:2969
void ast_channel_set_writeformat(struct ast_channel *chan, struct ast_format *format)
@ AST_STATE_DOWN
Definition: channelstate.h:36
@ AST_STATE_UP
Definition: channelstate.h:42
static int hangup_channel(struct stasis_app_control *control, struct ast_channel *chan, void *data)
Definition: control.c:1205
@ E_MATCH
Definition: extconf.h:217
Media Format Cache API.
struct ast_format * ast_format_ulaw
Built-in cached ulaw format.
Definition: format_cache.c:86
@ AST_FORMAT_CAP_FLAG_DEFAULT
Definition: format_cap.h:38
#define ast_format_cap_append(cap, format, framing)
Add format capability to capabilities structure.
Definition: format_cap.h:99
#define ast_format_cap_alloc(flags)
Allocate a new ast_format_cap structure.
Definition: format_cap.h:49
static const char name[]
Definition: format_mp3.c:68
struct ast_frame ast_null_frame
Definition: main/frame.c:79
#define LOG_ERROR
int errno
Asterisk module definitions.
def info(msg)
struct ast_bridge * park_application_setup(struct ast_channel *parkee, struct ast_channel *parker, const char *app_data, int *silence_announcements)
Function to prepare a channel for parking by determining which parking bridge should be used,...
struct parked_user * parking_lot_retrieve_parked_user(struct parking_lot *lot, int target)
Determine if there is a parked user in a parking space and pull it from the parking lot if there is.
void unload_parking_tests(void)
Unregister parking unit tests.
int load_parking_tests(void)
Register parking unit tests.
Core PBX routines and definitions.
const char * ast_get_extension_app(struct ast_exten *e)
Definition: pbx.c:8557
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name.
struct ast_exten * pbx_find_extension(struct ast_channel *chan, struct ast_context *bypass, struct pbx_find_info *q, const char *context, const char *exten, int priority, const char *label, const char *callerid, enum ext_match_t action)
Definition: ael_main.c:152
static void * cleanup(void *unused)
Definition: pbx_realtime.c:124
Call Parking Resource Internal API.
@ PARK_ANSWERED
Definition: res_parking.h:45
@ PARKINGLOT_DISABLED
Definition: res_parking.h:61
struct parking_lot * parking_lot_build_or_update(struct parking_lot_cfg *cfg, int dynamic)
If a parking lot exists in the parking lot list already, update its status to match the provided conf...
Definition: res_parking.c:869
struct parking_lot * parking_lot_find_by_name(const char *lot_name)
Find a parking lot based on its name.
Definition: res_parking.c:602
int parking_lot_remove_if_unused(struct parking_lot *lot)
Remove a parking lot from the usable lists if it is no longer involved in any calls and no configurat...
Definition: res_parking.c:400
int parking_lot_cfg_create_extensions(struct parking_lot_cfg *lot_cfg)
Add extensions for a parking lot configuration.
Definition: res_parking.c:759
#define NULL
Definition: resample.c:96
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:521
Structure that contains information about a bridge.
Definition: bridge.h:349
Structure to describe a channel "technology", ie a channel driver See for examples:
Definition: channel.h:648
const char *const type
Definition: channel.h:649
Main Channel structure associated with a channel.
ast_exten: An extension The dialplan is saved as a linked list with each context having it's own link...
Definition: pbx.c:237
Format capabilities structure, holds formats + preference order + etc.
Definition: format_cap.c:54
Data structure associated with a single frame of data.
Caller Party information.
Definition: channel.h:420
struct ast_party_id id
Caller party ID.
Definition: channel.h:422
struct ast_party_name name
Subscriber name.
Definition: channel.h:342
char * str
Subscriber name (Malloced)
Definition: channel.h:266
char * parker_dial_string
Definition: res_parking.h:111
enum park_call_resolution resolution
Definition: res_parking.h:114
unsigned int time_limit
Definition: res_parking.h:112
int parking_space
Definition: res_parking.h:109
unsigned int parkingtime
Definition: res_parking.h:69
const ast_string_field comebackcontext
Definition: res_parking.h:89
unsigned int parkfindnext
Definition: res_parking.h:71
unsigned int parkext_exclusive
Definition: res_parking.h:72
const ast_string_field parkext
Definition: res_parking.h:89
unsigned int comebackdialtime
Definition: res_parking.h:70
const ast_string_field parking_con
Definition: res_parking.h:89
enum parking_lot_modes mode
Definition: res_parking.h:97
struct ast_bridge * parking_bridge
Definition: res_parking.h:94
const ast_string_field name
Definition: res_parking.h:102
int stacklen
Definition: extconf.h:237
Test Framework API.
@ TEST_INIT
Definition: test.h:200
@ TEST_EXECUTE
Definition: test.h:201
#define AST_TEST_REGISTER(cb)
Definition: test.h:127
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
#define AST_TEST_UNREGISTER(cb)
Definition: test.h:128
#define AST_TEST_DEFINE(hdr)
Definition: test.h:126
@ AST_TEST_PASS
Definition: test.h:195
@ AST_TEST_FAIL
Definition: test.h:196
@ AST_TEST_NOT_RUN
Definition: test.h:194
#define CHANNEL_TECH_NAME
Definition: test_bridging.c:45
static void safe_channel_release(struct ast_channel *chan)
#define TEST_CATEGORY
Definition: test_bridging.c:43
static void do_sleep(struct timespec *to_sleep)
Definition: test_cdr.c:387
static struct timespec to_sleep
A 1 second sleep.
Definition: test_cel.c:85
Time-related functions and macros.
Utility functions.
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:941