39 #if defined(TEST_FRAMEWORK)
41 #define TEST_CATEGORY "/res/parking/"
43 #define CHANNEL_TECH_NAME "ParkingTestChannel"
48 .id.number.str =
"100",
63 .type = CHANNEL_TECH_NAME,
64 .description =
"Parking unit test technology",
65 .write = parking_test_write,
66 .read = parking_test_read,
70 static int set_test_formats(
struct ast_channel *chan)
80 ast_channel_nativeformats_set(chan, caps);
91 static struct ast_channel *create_alice_channel(
void)
94 "100",
"Alice",
"100",
"100",
"default", NULL, NULL, 0,
95 CHANNEL_TECH_NAME
"/Alice");
101 if (set_test_formats(alice)) {
102 ast_channel_unlock(alice);
107 ast_channel_tech_set(alice, &parking_test_tech);
111 ast_channel_unlock(alice);
119 ast_channel_hangupcause_set(chan, hangup_cause);
124 static void safe_channel_release(
struct ast_channel *chan)
132 static void do_sleep(
struct timespec *
to_sleep)
134 while ((nanosleep(to_sleep, to_sleep) == -1) && (errno == EINTR)) {
138 #define TEST_LOT_NAME "unit_tests_res_parking_test_lot"
140 static 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)
145 test_cfg = parking_lot_cfg_create(name);
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;
161 ast_test_status_update(test,
"Extensions for parking lot '%s' could not be registered. Extension Creation failed.\n", name);
173 static int dispose_test_lot(
struct parking_lot *test_lot,
int expect_destruction)
182 if ((expect_destruction && !found_lot) || (!expect_destruction && found_lot)) {
196 info->name =
"create_lot";
197 info->category = TEST_CATEGORY;
198 info->summary =
"Parking lot creation";
200 "Creates a parking lot and then disposes of it.";
201 return AST_TEST_NOT_RUN;
206 ast_test_status_update(test,
"Creating test parking lot '%s'\n", TEST_LOT_NAME);
208 test_lot = generate_test_parking_lot(TEST_LOT_NAME, 701, 703, NULL,
"unit_test_res_parking_create_lot_con", test);
210 ast_test_status_update(test,
"Failed to create test parking lot. Test Failed\n");
211 return AST_TEST_FAIL;
214 ast_test_status_update(test,
"Successfully created parking lot. Retrieving test parking lot from container.\n");
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;
223 ast_test_status_update(test,
"Successfully retrieved parking lot. Removing test parking lot from container.\n");
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");
229 ast_test_status_update(test,
"Parking lot was successfully removed from the container. Test complete.\n");
231 return AST_TEST_PASS;
240 struct timespec to_sleep = {1, 0};
244 info->name =
"park_channel";
245 info->category = TEST_CATEGORY;
246 info->summary =
"Park a Channel";
248 "Creates a parking lot, parks a channel in it, then removes it from the parking lot bridge.";
249 return AST_TEST_NOT_RUN;
254 ast_test_status_update(test,
"Creating test parking lot '%s'\n", TEST_LOT_NAME);
256 test_lot = generate_test_parking_lot(TEST_LOT_NAME, 701, 703, NULL,
"unit_test_res_parking_create_lot_con", test);
258 ast_test_status_update(test,
"Failed to create test parking lot. Test failed.\n");
259 return AST_TEST_FAIL;
262 chan_alice = create_alice_channel();
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;
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;
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;
290 chan_alice = hangup_channel(chan_alice, AST_CAUSE_NORMAL);
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;
297 return AST_TEST_PASS;
301 static int parked_users_match(
const struct parked_user *actual,
const struct parked_user *expected,
struct ast_test *test)
314 ast_test_status_update(test,
"time_limit expected: %u - got: %u\n", expected->
time_limit, actual->
time_limit);
319 ast_test_status_update(test,
"resolution expected: %u - got: %u\n", expected->
resolution, actual->
resolution);
334 ast_test_status_update(test,
"parking_stop expected: %d - got: %d\n", expected->
parking_stop, actual->
parking_stop);
339 ast_test_status_update(test,
"parkingtime expected: %u - got: %u\n", expected->
parkingtime, actual->
parkingtime);
349 ast_test_status_update(test,
"parkfindnext expected: %u - got: %u\n", expected->
parkfindnext, actual->
parkfindnext);
359 ast_test_status_update(test,
"parkext expected: %s - got: %s\n", expected->
parkext, actual->
parkext);
364 ast_test_status_update(test,
"parking_con expected: %s - got: %s\n", expected->
parking_con, actual->
parking_con);
383 struct timespec to_sleep = {1, 0};
388 .parker_dial_string =
"ParkingTestChannel/Alice",
395 info->name =
"park_retrieve";
396 info->category = TEST_CATEGORY;
397 info->summary =
"Retrieve a parked channel";
399 "Creates a parking lot, parks a channel in it, then removes it from the parking lot bridge.";
400 return AST_TEST_NOT_RUN;
405 ast_test_status_update(test,
"Creating test parking lot '%s'\n", TEST_LOT_NAME);
407 test_lot = generate_test_parking_lot(TEST_LOT_NAME, 701, 703, NULL,
"unit_test_res_parking_create_lot_con", test);
409 ast_test_status_update(test,
"Failed to create test parking lot. Test failed.\n");
410 return AST_TEST_FAIL;
413 chan_alice = create_alice_channel();
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;
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;
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;
440 if (!retrieved_user) {
441 ast_test_status_update(test,
"Failed to retrieve the parked user from the expected parking space. Test failed.\n");
446 ast_test_status_update(test,
"Successfully retrieved parked user from the parking lot. Validating user data.\n");
448 if (!parked_users_match(retrieved_user, &expected_user, test)) {
449 ast_test_status_update(test,
"Parked user validation failed\n");
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");
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");
468 return failure ? AST_TEST_FAIL : AST_TEST_PASS;
471 static int check_retrieve_call_extensions(
struct ast_test *test,
int expected)
476 char search_buffer[4];
479 check = pbx_find_extension(NULL, NULL, &find_info,
"unit_test_res_parking_create_lot_con",
"700", 1, NULL, NULL, E_MATCH);
481 if (check ? !expected : expected) {
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");
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));
497 for (extens = 701; extens <= 703; extens++) {
498 sprintf(search_buffer,
"%d", extens);
499 find_info.stacklen = 0;
501 check = pbx_find_extension(NULL, NULL, &find_info,
"unit_test_res_parking_create_lot_con", search_buffer, 1, NULL, NULL, E_MATCH);
503 if (check ? !expected : expected) {
505 ast_test_status_update(test,
"An extension '%s' was %s when it %s have been. Test failed.\n",
507 expected ?
"not present" :
"present",
508 expected ?
"should" :
"should not");
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",
514 ast_get_extension_app(check));
530 info->name =
"park_extensions";
531 info->category = TEST_CATEGORY;
532 info->summary =
"Parking lot extension creation tests";
534 "Creates parking lots and checks that they registered the expected extensions, then removes them.";
535 return AST_TEST_NOT_RUN;
540 test_lot = generate_test_parking_lot(TEST_LOT_NAME, 701, 703,
"700",
"unit_test_res_parking_create_lot_con", test);
542 ast_test_status_update(test,
"Failed to create test parking lot. Test Failed.\n");
543 return AST_TEST_FAIL;
546 if (check_retrieve_call_extensions(test, 1)) {
547 dispose_test_lot(test_lot, 1);
548 return AST_TEST_FAIL;
551 ast_test_status_update(test,
"Extensions for the test parking lot were verified. Cleaning up and verifying their removal.\n");
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;
557 ao2_cleanup(test_lot);
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;
565 ast_test_status_update(test,
"Extensions for the test parking lot verified as removed. Test completed successfully.\n");
567 return AST_TEST_PASS;
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";
591 "Creates parking lots with overlapping extensions to test for conflicts";
592 return AST_TEST_NOT_RUN;
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);
601 ast_test_status_update(test,
"Failed to create the base parking lot. Test failed.\n");
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",
613 ast_test_status_update(test,
"%s was successfully created when it was expected to fail. Test failed.\n", cur_lot_name);
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",
623 ast_test_status_update(test,
"%s was successfully created when it was expected to fail. Test failed.\n", cur_lot_name);
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",
633 ast_test_status_update(test,
"%s was successfully created when it was expected to fail. Test failed.\n", cur_lot_name);
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",
643 ast_test_status_update(test,
"%s was successfully created when it was expected to fail. Test failed.\n", cur_lot_name);
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",
652 if (!expect_success1) {
653 ast_test_status_update(test,
"%s failed to be created. Success was expected. Test failed.\n", cur_lot_name);
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",
662 if (!expect_success2) {
663 ast_test_status_update(test,
"%s failed to be created. Success was expected. Test failed.\n", cur_lot_name);
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",
672 if (!expect_success3) {
673 ast_test_status_update(test,
"%s failed to be created. Success was expected. Test failed.\n", cur_lot_name);
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",
682 if (!expect_success4) {
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");
694 dispose_test_lot(expect_fail1, 1);
699 dispose_test_lot(expect_fail2, 1);
704 dispose_test_lot(expect_fail3, 1);
709 dispose_test_lot(expect_fail4, 1);
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");
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");
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");
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");
732 return failed ? AST_TEST_FAIL : AST_TEST_PASS;
746 info->name =
"dynamic_parking_variables";
747 info->category = TEST_CATEGORY;
748 info->summary =
"Tests whether dynamic parking lot creation respects channel variables";
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;
756 ast_test_status_update(test,
"Creating expected configuration for dynamic parking lot\n");
758 expected_cfg = parking_lot_cfg_create(
"unit_tests_res_parking_test_lot_dynamic");
761 ast_test_status_update(test,
"Failed to create expected configuration. Test failed.\n");
762 return AST_TEST_FAIL;
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;
773 ast_string_field_set(expected_cfg, comebackcontext,
"unit_test_res_parking_create_lot_comeback");
775 ast_test_status_update(test,
"Creating template lot\n");
777 template_lot = generate_test_parking_lot(TEST_LOT_NAME, 701, 703,
"700",
"unit_test_res_parking_create_lot_con", test);
780 ast_test_status_update(test,
"Failed to generate template lot. Test failed.\n");
781 return AST_TEST_FAIL;
784 ast_test_status_update(test,
"Creating Alice channel to test dynamic parking lot creation.\n");
786 chan_alice = create_alice_channel();
789 ast_test_status_update(test,
"Failed to create Alice channel. Test failed.\n");
794 ast_test_status_update(test,
"Setting Dynamic Parking channel variables on Alice.\n");
802 ast_test_status_update(test,
"Generating dynamic parking lot based on Alice's channel variables.\n");
804 dynamic_lot = parking_create_dynamic_lot_forced(
"unit_tests_res_parking_test_lot_dynamic", chan_alice);
807 ast_test_status_update(test,
"Failed to create dynamic parking lot. Test failed.\n");
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");
819 ast_test_status_update(test,
"Dynamic parking lot created successfully and matches expectations. Test passed.\n");
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");
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");
832 return failed ? AST_TEST_FAIL : AST_TEST_PASS;
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);
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);
Main Channel structure associated with a channel.
Asterisk main include file. File version handling, generic pbx functions.
ast_exten: An extension The dialplan is saved as a linked list with each context having it's own link...
unsigned int comebackdialtime
Time-related functions and macros.
struct ast_party_name name
Subscriber name.
struct ast_bridge * parking_bridge
struct ast_channel * ast_channel_release(struct ast_channel *chan)
Unlink and release reference to a channel.
int load_parking_tests(void)
Register parking unit tests.
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.
char * str
Subscriber name (Malloced)
const ast_string_field comebackcontext
static struct timespec to_sleep
A 1 second sleep.
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...
int parking_lot_cfg_create_extensions(struct parking_lot_cfg *lot_cfg)
Add extensions for a parking lot configuration.
struct ast_party_id id
Caller party ID.
static void cleanup(void)
Clean up any old apps that we don't need any more.
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)
const ast_string_field parking_con
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...
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...
char * parker_dial_string
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Caller Party information.
Structure to describe a channel "technology", ie a channel driver See for examples: ...
enum park_call_resolution resolution
Core PBX routines and definitions.
Structure that contains information about a bridge.
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...
int ast_bridge_depart(struct ast_channel *chan)
Depart a channel from a bridge.
void unload_parking_tests(void)
Unregister parking unit tests.
unsigned int parkfindnext
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
const ast_string_field name
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_frame ast_null_frame
enum parking_lot_modes mode
const ast_string_field parkext
Data structure associated with a single frame of data.
Internal Asterisk hangup causes.
#define AST_TEST_DEFINE(hdr)
struct parking_lot * parking_lot_find_by_name(const char *lot_name)
Find a parking lot based on its name.
Call Parking Resource Internal API.
#define ast_channel_alloc(needqueue, state, cid_num, cid_name, acctcode, exten, context, assignedids, requestor, amaflag,...)
Create a channel structure.
Asterisk module definitions.
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
unsigned int parkext_exclusive
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.