git migration: Refactor the ASTERISK_FILE_VERSION macro
[asterisk/asterisk.git] / res / parking / parking_tests.c
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 ASTERISK_REGISTER_FILE()
29
30 #include "res_parking.h"
31 #include "asterisk/utils.h"
32 #include "asterisk/module.h"
33 #include "asterisk/astobj2.h"
34 #include "asterisk/test.h"
35 #include "asterisk/stringfields.h"
36 #include "asterisk/time.h"
37 #include "asterisk/causes.h"
38 #include "asterisk/pbx.h"
39 #include "asterisk/format_cache.h"
40
41 #if defined(TEST_FRAMEWORK)
42
43 #define TEST_CATEGORY "/res/parking/"
44
45 #define CHANNEL_TECH_NAME "ParkingTestChannel"
46
47 static const struct ast_party_caller alice_callerid = {
48         .id.name.str = "Alice",
49         .id.name.valid = 1,
50         .id.number.str = "100",
51         .id.number.valid = 1,
52 };
53
54 static int parking_test_write(struct ast_channel *chan, struct ast_frame *frame)
55 {
56         return 0;
57 }
58
59 static struct ast_frame *parking_test_read(struct ast_channel *chan)
60 {
61         return &ast_null_frame;
62 }
63
64 static const struct ast_channel_tech parking_test_tech = {
65         .type = CHANNEL_TECH_NAME,
66         .description = "Parking unit test technology",
67         .write = parking_test_write,
68         .read = parking_test_read,
69 };
70
71 /*! \brief Set ulaw format on the channel */
72 static int set_test_formats(struct ast_channel *chan)
73 {
74         struct ast_format_cap *caps;
75
76         caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
77         if (!caps) {
78                 return -1;
79         }
80
81         ast_format_cap_append(caps, ast_format_ulaw, 0);
82         ast_channel_nativeformats_set(chan, caps);
83         ast_channel_set_writeformat(chan, ast_format_ulaw);
84         ast_channel_set_rawwriteformat(chan, ast_format_ulaw);
85         ast_channel_set_readformat(chan, ast_format_ulaw);
86         ast_channel_set_rawreadformat(chan, ast_format_ulaw);
87         ao2_ref(caps, -1);
88
89         return 0;
90 }
91
92 /*! \brief Create a \ref test_cdr_chan_tech for Alice */
93 static struct ast_channel *create_alice_channel(void)
94 {
95         struct ast_channel *alice = ast_channel_alloc(0, AST_STATE_DOWN,
96                 "100", "Alice", "100", "100", "default", NULL, NULL, 0,
97                 CHANNEL_TECH_NAME "/Alice");
98
99         if (!alice) {
100                 return NULL;
101         }
102
103         if (set_test_formats(alice)) {
104                 ast_channel_unlock(alice);
105                 ast_channel_release(alice);
106                 return NULL;
107         }
108
109         ast_channel_tech_set(alice, &parking_test_tech);
110
111         ast_channel_set_caller(alice, &alice_callerid, NULL);
112
113         ast_channel_unlock(alice);
114
115         return alice;
116 }
117
118 /*! \brief Hang up a test channel safely */
119 static struct ast_channel *hangup_channel(struct ast_channel *chan, int hangup_cause)
120 {
121         ast_channel_hangupcause_set(chan, hangup_cause);
122         ast_hangup(chan);
123         return NULL;
124 }
125
126 static void safe_channel_release(struct ast_channel *chan)
127 {
128         if (!chan) {
129                 return;
130         }
131         ast_channel_release(chan);
132 }
133
134 static void do_sleep(struct timespec *to_sleep)
135 {
136         while ((nanosleep(to_sleep, to_sleep) == -1) && (errno == EINTR)) {
137         }
138 }
139
140 #define TEST_LOT_NAME "unit_tests_res_parking_test_lot"
141
142 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)
143 {
144         RAII_VAR(struct parking_lot_cfg *, test_cfg, NULL, ao2_cleanup);
145         struct parking_lot *test_lot;
146
147         test_cfg = parking_lot_cfg_create(name);
148         if (!test_cfg) {
149                 return NULL;
150         }
151
152         test_cfg->parking_start = low_space;
153         test_cfg->parking_stop = high_space;
154         test_cfg->parkingtime = 10;
155         test_cfg->comebackdialtime = 10;
156         test_cfg->parkfindnext = 1;
157         test_cfg->parkext_exclusive = 1;
158         ast_string_field_set(test_cfg, parkext, park_exten);
159         ast_string_field_set(test_cfg, parking_con, park_context);
160         ast_string_field_set(test_cfg, comebackcontext, "unit_test_res_parking_create_lot_comeback");
161
162         if (parking_lot_cfg_create_extensions(test_cfg)) {
163                 ast_test_status_update(test, "Extensions for parking lot '%s' could not be registered. Extension Creation failed.\n", name);
164                 return NULL;
165         }
166
167         test_lot = parking_lot_build_or_update(test_cfg, 1);
168         if (!test_lot) {
169                 return NULL;
170         }
171
172         return test_lot;
173 }
174
175 static int dispose_test_lot(struct parking_lot *test_lot, int expect_destruction)
176 {
177         RAII_VAR(struct parking_lot *, found_lot, NULL, ao2_cleanup);
178
179         test_lot->mode = PARKINGLOT_DISABLED;
180         parking_lot_remove_if_unused(test_lot);
181
182         found_lot = parking_lot_find_by_name(test_lot->name);
183
184         if ((expect_destruction && !found_lot) || (!expect_destruction && found_lot)) {
185                 return 0;
186         }
187
188         return -1;
189 }
190
191 AST_TEST_DEFINE(create_lot)
192 {
193         RAII_VAR(struct parking_lot *, test_lot, NULL, ao2_cleanup);
194         RAII_VAR(struct parking_lot *, found_copy, NULL, ao2_cleanup);
195
196         switch (cmd) {
197         case TEST_INIT:
198                 info->name = "create_lot";
199                 info->category = TEST_CATEGORY;
200                 info->summary = "Parking lot creation";
201                 info->description =
202                         "Creates a parking lot and then disposes of it.";
203                 return AST_TEST_NOT_RUN;
204         case TEST_EXECUTE:
205                 break;
206         }
207
208         ast_test_status_update(test, "Creating test parking lot '%s'\n", TEST_LOT_NAME);
209
210         test_lot = generate_test_parking_lot(TEST_LOT_NAME, 701, 703, NULL, "unit_test_res_parking_create_lot_con", test);
211         if (!test_lot) {
212                 ast_test_status_update(test, "Failed to create test parking lot. Test Failed\n");
213                 return AST_TEST_FAIL;
214         }
215
216         ast_test_status_update(test, "Successfully created parking lot. Retrieving test parking lot from container.\n");
217
218         found_copy = parking_lot_find_by_name(TEST_LOT_NAME);
219         if (!found_copy) {
220                 ast_test_status_update(test, "Failed to find parking lot in the parking lot container. Test failed.\n");
221                 dispose_test_lot(test_lot, 1);
222                 return AST_TEST_FAIL;
223         }
224
225         ast_test_status_update(test, "Successfully retrieved parking lot. Removing test parking lot from container.\n");
226
227         if (dispose_test_lot(found_copy, 1)) {
228                 ast_test_status_update(test, "Found parking lot in container after attempted removal. Test failed.\n");
229         }
230
231         ast_test_status_update(test, "Parking lot was successfully removed from the container. Test complete.\n");
232
233         return AST_TEST_PASS;
234 }
235
236 AST_TEST_DEFINE(park_call)
237 {
238         RAII_VAR(struct parking_lot *, test_lot, NULL, ao2_cleanup);
239         RAII_VAR(struct ast_channel *, chan_alice, NULL, safe_channel_release);
240         RAII_VAR(struct ast_bridge *, parking_bridge, NULL, ao2_cleanup);
241
242         struct timespec to_sleep = {1, 0};
243
244         switch (cmd) {
245         case TEST_INIT:
246                 info->name = "park_channel";
247                 info->category = TEST_CATEGORY;
248                 info->summary = "Park a Channel";
249                 info->description =
250                         "Creates a parking lot, parks a channel in it, then removes it from the parking lot bridge.";
251                 return AST_TEST_NOT_RUN;
252         case TEST_EXECUTE:
253                 break;
254         }
255
256         ast_test_status_update(test, "Creating test parking lot '%s'\n", TEST_LOT_NAME);
257
258         test_lot = generate_test_parking_lot(TEST_LOT_NAME, 701, 703, NULL, "unit_test_res_parking_create_lot_con", test);
259         if (!test_lot) {
260                 ast_test_status_update(test, "Failed to create test parking lot. Test failed.\n");
261                 return AST_TEST_FAIL;
262         }
263
264         chan_alice = create_alice_channel();
265         if (!chan_alice) {
266                 ast_test_status_update(test, "Failed to create test channel to park. Test failed.\n");
267                 dispose_test_lot(test_lot, 1);
268                 return AST_TEST_FAIL;
269         }
270
271         ast_channel_state_set(chan_alice, AST_STATE_UP);
272         pbx_builtin_setvar_helper(chan_alice, "BLINDTRANSFER", ast_channel_name(chan_alice));
273
274         parking_bridge = park_application_setup(chan_alice, chan_alice, TEST_LOT_NAME, NULL);
275         if (!parking_bridge) {
276                 ast_test_status_update(test, "Failed to get the parking bridge for '%s'. Test failed.\n", TEST_LOT_NAME);
277                 dispose_test_lot(test_lot, 1);
278                 return AST_TEST_FAIL;
279         }
280
281         if (ast_bridge_impart(parking_bridge, chan_alice, NULL, NULL,
282                 AST_BRIDGE_IMPART_CHAN_DEPARTABLE)) {
283                 ast_test_status_update(test, "Failed to impart alice into parking lot. Test failed.\n");
284                 dispose_test_lot(test_lot, 1);
285                 return AST_TEST_FAIL;
286         }
287
288         do_sleep(&to_sleep);
289
290         ast_bridge_depart(chan_alice);
291
292         chan_alice = hangup_channel(chan_alice, AST_CAUSE_NORMAL);
293
294         if (dispose_test_lot(test_lot, 1)) {
295                 ast_test_status_update(test, "Found parking lot in container after attempted removal. Test failed.\n");
296                 return AST_TEST_FAIL;
297         }
298
299         return AST_TEST_PASS;
300
301 }
302
303 static int parked_users_match(const struct parked_user *actual, const struct parked_user *expected, struct ast_test *test)
304 {
305         if (expected->parking_space != actual->parking_space) {
306                 ast_test_status_update(test, "parking_space expected: %d - got: %d\n", expected->parking_space, actual->parking_space);
307                 return 0;
308         }
309
310         if (strcmp(expected->parker_dial_string, actual->parker_dial_string)) {
311                 ast_test_status_update(test, "parker_dial_string expected: %s - got: %s\n", expected->parker_dial_string, actual->parker_dial_string);
312                 return 0;
313         }
314
315         if (expected->time_limit != actual->time_limit) {
316                 ast_test_status_update(test, "time_limit expected: %u - got: %u\n", expected->time_limit, actual->time_limit);
317                 return 0;
318         }
319
320         if (expected->resolution != actual->resolution) {
321                 ast_test_status_update(test, "resolution expected: %u - got: %u\n", expected->resolution, actual->resolution);
322                 return 0;
323         }
324
325         return 1;
326 }
327
328 static int parking_lot_cfgs_match(const struct parking_lot_cfg *actual, const struct parking_lot_cfg *expected, struct ast_test *test)
329 {
330         if (expected->parking_start != actual->parking_start) {
331                 ast_test_status_update(test, "parking_start expected: %d - got: %d\n", expected->parking_start, actual->parking_start);
332                 return 0;
333         }
334
335         if (expected->parking_stop != actual->parking_stop) {
336                 ast_test_status_update(test, "parking_stop expected: %d - got: %d\n", expected->parking_stop, actual->parking_stop);
337                 return 0;
338         }
339
340         if (expected->parkingtime != actual->parkingtime) {
341                 ast_test_status_update(test, "parkingtime expected: %u - got: %u\n", expected->parkingtime, actual->parkingtime);
342                 return 0;
343         }
344
345         if (expected->comebackdialtime != actual->comebackdialtime) {
346                 ast_test_status_update(test, "comebackdialtime expected: %u - got: %u\n", expected->comebackdialtime, actual->comebackdialtime);
347                 return 0;
348         }
349
350         if (expected->parkfindnext != actual->parkfindnext) {
351                 ast_test_status_update(test, "parkfindnext expected: %u - got: %u\n", expected->parkfindnext, actual->parkfindnext);
352                 return 0;
353         }
354
355         if (expected->parkext_exclusive != actual->parkext_exclusive) {
356                 ast_test_status_update(test, "parkext_exclusive expected: %u - got: %u\n", expected->parkext_exclusive, actual->parkext_exclusive);
357                 return 0;
358         }
359
360         if (strcmp(expected->parkext, actual->parkext)) {
361                 ast_test_status_update(test, "parkext expected: %s - got: %s\n", expected->parkext, actual->parkext);
362                 return 0;
363         }
364
365         if (strcmp(expected->parking_con, actual->parking_con)) {
366                 ast_test_status_update(test, "parking_con expected: %s - got: %s\n", expected->parking_con, actual->parking_con);
367                 return 0;
368         }
369
370         if (strcmp(expected->comebackcontext, actual->comebackcontext)) {
371                 ast_test_status_update(test, "comebackcontext expected: %s - got: %s\n", expected->comebackcontext, actual->comebackcontext);
372                 return 0;
373         }
374
375         return 1;
376 }
377
378 AST_TEST_DEFINE(retrieve_call)
379 {
380         RAII_VAR(struct parking_lot *, test_lot, NULL, ao2_cleanup);
381         RAII_VAR(struct ast_channel *, chan_alice, NULL, safe_channel_release);
382         RAII_VAR(struct ast_bridge *, parking_bridge, NULL, ao2_cleanup);
383         RAII_VAR(struct parked_user *, retrieved_user, NULL, ao2_cleanup);
384
385         struct timespec to_sleep = {1, 0};
386         int failure = 0;
387
388         static const struct parked_user expected_user = {
389                 .parking_space = 701,
390                 .parker_dial_string = "ParkingTestChannel/Alice",
391                 .time_limit = 10,
392                 .resolution = PARK_ANSWERED,
393         };
394
395         switch (cmd) {
396         case TEST_INIT:
397                 info->name = "park_retrieve";
398                 info->category = TEST_CATEGORY;
399                 info->summary = "Retrieve a parked channel";
400                 info->description =
401                         "Creates a parking lot, parks a channel in it, then removes it from the parking lot bridge.";
402                 return AST_TEST_NOT_RUN;
403         case TEST_EXECUTE:
404                 break;
405         }
406
407         ast_test_status_update(test, "Creating test parking lot '%s'\n", TEST_LOT_NAME);
408
409         test_lot = generate_test_parking_lot(TEST_LOT_NAME, 701, 703, NULL, "unit_test_res_parking_create_lot_con", test);
410         if (!test_lot) {
411                 ast_test_status_update(test, "Failed to create test parking lot. Test failed.\n");
412                 return AST_TEST_FAIL;
413         }
414
415         chan_alice = create_alice_channel();
416         if (!chan_alice) {
417                 ast_test_status_update(test, "Failed to create test channel to park. Test failed.\n");
418                 dispose_test_lot(test_lot, 1);
419                 return AST_TEST_FAIL;
420         }
421
422         ast_channel_state_set(chan_alice, AST_STATE_UP);
423         pbx_builtin_setvar_helper(chan_alice, "BLINDTRANSFER", ast_channel_name(chan_alice));
424
425         parking_bridge = park_application_setup(chan_alice, chan_alice, TEST_LOT_NAME, NULL);
426         if (!parking_bridge) {
427                 ast_test_status_update(test, "Failed to get the parking bridge for '%s'. Test failed.\n", TEST_LOT_NAME);
428                 dispose_test_lot(test_lot, 1);
429                 return AST_TEST_FAIL;
430         }
431
432         if (ast_bridge_impart(parking_bridge, chan_alice, NULL, NULL,
433                 AST_BRIDGE_IMPART_CHAN_DEPARTABLE)) {
434                 ast_test_status_update(test, "Failed to impart alice into parking lot. Test failed.\n");
435                 dispose_test_lot(test_lot, 1);
436                 return AST_TEST_FAIL;
437         }
438
439         do_sleep(&to_sleep);
440
441         retrieved_user = parking_lot_retrieve_parked_user(test_lot, 701);
442         if (!retrieved_user) {
443                 ast_test_status_update(test, "Failed to retrieve the parked user from the expected parking space. Test failed.\n");
444                 failure = 1;
445                 goto test_cleanup;
446         }
447
448         ast_test_status_update(test, "Successfully retrieved parked user from the parking lot. Validating user data.\n");
449
450         if (!parked_users_match(retrieved_user, &expected_user, test)) {
451                 ast_test_status_update(test, "Parked user validation failed\n");
452                 failure = 1;
453                 goto test_cleanup;
454         }
455
456         if (retrieved_user->chan != chan_alice) {
457                 ast_test_status_update(test, "The retrieved parked channel didn't match the expected channel. Test failed.\n");
458                 failure = 1;
459                 goto test_cleanup;
460         }
461
462 test_cleanup:
463         ast_bridge_depart(chan_alice);
464         chan_alice = hangup_channel(chan_alice, AST_CAUSE_NORMAL);
465         if (dispose_test_lot(test_lot, 1)) {
466                 ast_test_status_update(test, "Found parking lot in container after attempted removal. Test failed.\n");
467                 failure = 1;
468         }
469
470         return failure ? AST_TEST_FAIL : AST_TEST_PASS;
471 }
472
473 static int check_retrieve_call_extensions(struct ast_test *test, int expected)
474 {
475         struct ast_exten *check;
476         struct pbx_find_info find_info = { .stacklen = 0 }; /* the rest is reset in pbx_find_extension */
477         int extens;
478         char search_buffer[4];
479
480         /* Check the parking extensions */
481         check = pbx_find_extension(NULL, NULL, &find_info, "unit_test_res_parking_create_lot_con", "700", 1, NULL, NULL, E_MATCH);
482
483         if (check ? !expected : expected) {
484                 /* extension isn't present when it should be or is present when it shouldn't be. Automatic failure. */
485                 ast_test_status_update(test, "An extension '700' was %s when it %s have been. Test failed.\n",
486                         expected ? "not present" : "present",
487                         expected ? "should" : "should not");
488                 return -1;
489         } else if (check && expected) {
490                 if (strcmp(ast_get_extension_app(check), "Park")) {
491                         ast_test_status_update(test, "An extension '700' has the wrong application associated with it. Got '%s' expected 'Park'.\n",
492                                 ast_get_extension_app(check));
493                         return -1;
494                 }
495         }
496
497
498         /* Check the parking space extensions 701-703 */
499         for (extens = 701; extens <= 703; extens++) {
500                 sprintf(search_buffer, "%d", extens);
501                 find_info.stacklen = 0; /* reset for pbx_find_extension */
502
503                 check = pbx_find_extension(NULL, NULL, &find_info, "unit_test_res_parking_create_lot_con", search_buffer, 1, NULL, NULL, E_MATCH);
504
505                 if (check ? !expected : expected) {
506                         /* extension isn't present when it should be or is present when it shouldn't be. Automatic failure. */
507                         ast_test_status_update(test, "An extension '%s' was %s when it %s have been. Test failed.\n",
508                                 search_buffer,
509                                 expected ? "not present" : "present",
510                                 expected ? "should" : "should not");
511                         return -1;
512                 } else if (check && expected) {
513                         if (strcmp(ast_get_extension_app(check), "ParkedCall")) {
514                                 ast_test_status_update(test, "An extension '%s' has the wrong application associated with it. Got '%s', expected 'ParkedCall'.\n",
515                                         search_buffer,
516                                         ast_get_extension_app(check));
517                                 return -1;
518                         }
519                 }
520         }
521
522         return 0;
523
524 }
525
526 AST_TEST_DEFINE(park_extensions)
527 {
528         RAII_VAR(struct parking_lot *, test_lot, NULL, ao2_cleanup);
529
530         switch (cmd) {
531         case TEST_INIT:
532                 info->name = "park_extensions";
533                 info->category = TEST_CATEGORY;
534                 info->summary = "Parking lot extension creation tests";
535                 info->description =
536                         "Creates parking lots and checks that they registered the expected extensions, then removes them.";
537                 return AST_TEST_NOT_RUN;
538         case TEST_EXECUTE:
539                 break;
540         }
541
542         test_lot = generate_test_parking_lot(TEST_LOT_NAME, 701, 703, "700", "unit_test_res_parking_create_lot_con", test);
543         if (!test_lot) {
544                 ast_test_status_update(test, "Failed to create test parking lot. Test Failed.\n");
545                 return AST_TEST_FAIL;
546         }
547
548         if (check_retrieve_call_extensions(test, 1)) {
549                 dispose_test_lot(test_lot, 1);
550                 return AST_TEST_FAIL;
551         }
552
553         ast_test_status_update(test, "Extensions for the test parking lot were verified. Cleaning up and verifying their removal.\n");
554
555         if (dispose_test_lot(test_lot, 1)) {
556                 ast_test_status_update(test, "Found parking lot in container after attempted removal. Test failed.\n");
557                 return AST_TEST_FAIL;
558         }
559         ao2_cleanup(test_lot);
560         test_lot = NULL;
561
562         if (check_retrieve_call_extensions(test, 0)) {
563                 ast_log(LOG_ERROR, "Test 'park_extensions' failed to clean up after itself properly.\n");
564                 return AST_TEST_FAIL;
565         }
566
567         ast_test_status_update(test, "Extensions for the test parking lot verified as removed. Test completed successfully.\n");
568
569         return AST_TEST_PASS;
570 }
571
572 AST_TEST_DEFINE(extension_conflicts)
573 {
574         RAII_VAR(struct parking_lot *, base_lot, NULL, ao2_cleanup);
575         RAII_VAR(struct parking_lot *, expect_fail1, NULL, ao2_cleanup); /* Failure due to overlapping parkexten */
576         RAII_VAR(struct parking_lot *, expect_fail2, NULL, ao2_cleanup); /* Failure due to overlapping spaces */
577         RAII_VAR(struct parking_lot *, expect_fail3, NULL, ao2_cleanup); /* parkexten overlaps parking spaces */
578         RAII_VAR(struct parking_lot *, expect_fail4, NULL, ao2_cleanup); /* parking spaces overlap parkexten */
579         RAII_VAR(struct parking_lot *, expect_success1, NULL, ao2_cleanup); /* Success due to being in a different context */
580         RAII_VAR(struct parking_lot *, expect_success2, NULL, ao2_cleanup); /* Success due to not having overlapping extensions */
581         RAII_VAR(struct parking_lot *, expect_success3, NULL, ao2_cleanup); /* Range of parking spaces differs by one above */
582         RAII_VAR(struct parking_lot *, expect_success4, NULL, ao2_cleanup); /* Range of parking spaces differs by one below */
583         char *cur_lot_name;
584
585         int failed = 0;
586
587         switch (cmd) {
588         case TEST_INIT:
589                 info->name = "extension_conflicts";
590                 info->category = TEST_CATEGORY;
591                 info->summary = "Tests the addition of parking lot extensions to make sure conflicts are detected";
592                 info->description =
593                         "Creates parking lots with overlapping extensions to test for conflicts";
594                 return AST_TEST_NOT_RUN;
595         case TEST_EXECUTE:
596                 break;
597         }
598
599         ast_test_status_update(test, "Creating the base lot. This should pass.\n");
600         base_lot = generate_test_parking_lot(TEST_LOT_NAME, 701, 703, "700", "unit_test_res_parking_create_lot_con", test);
601
602         if (!base_lot) {
603                 ast_test_status_update(test, "Failed to create the base parking lot. Test failed.\n");
604                 failed = 1;
605                 goto cleanup;
606         }
607
608         cur_lot_name = "unit_tests_res_parking_test_lot_fail1";
609         ast_test_status_update(test, "Creating a test lot which will overlap.\n");
610         expect_fail1 = generate_test_parking_lot(cur_lot_name,
611                 801, 803, "700", "unit_test_res_parking_create_lot_con", /* The parkexten overlaps the parkexten of the base */
612                 test);
613
614         if (expect_fail1) {
615                 ast_test_status_update(test, "%s was successfully created when it was expected to fail. Test failed.\n", cur_lot_name);
616                 failed = 1;
617                 goto cleanup;
618         }
619
620         cur_lot_name = "unit_tests_res_parking_test_lot_fail2";
621         expect_fail2 = generate_test_parking_lot(cur_lot_name,
622                 702, 705, "800", "unit_test_res_parking_create_lot_con", /* The range overlaps the range of the base */
623                 test);
624         if (expect_fail2) {
625                 ast_test_status_update(test, "%s was successfully created when it was expected to fail. Test failed.\n", cur_lot_name);
626                 failed = 1;
627                 goto cleanup;
628         }
629
630         cur_lot_name = "unit_tests_res_parking_test_lot_fail3";
631         expect_fail3 = generate_test_parking_lot(cur_lot_name,
632                 698, 700, "testfail3", "unit_test_res_parking_create_lot_con", /* The range overlaps the parkexten of the base */
633                 test);
634         if (expect_fail3) {
635                 ast_test_status_update(test, "%s was successfully created when it was expected to fail. Test failed.\n", cur_lot_name);
636                 failed = 1;
637                 goto cleanup;
638         }
639
640         cur_lot_name = "unit_tests_res_parking_test_lot_fail4";
641         expect_fail4 = generate_test_parking_lot(cur_lot_name,
642                 704, 706, "703", "unit_test_res_parking_create_lot_con", /* The parkexten overlaps the range of the base */
643                 test);
644         if (expect_fail4) {
645                 ast_test_status_update(test, "%s was successfully created when it was expected to fail. Test failed.\n", cur_lot_name);
646                 failed = 1;
647                 goto cleanup;
648         }
649
650         cur_lot_name = "unit_tests_res_parking_test_lot_success1";
651         expect_success1 = generate_test_parking_lot(cur_lot_name,
652                 701, 703, "700", "unit_test_res_parking_create_lot_con_2", /* no overlap due to different context */
653                 test);
654         if (!expect_success1) {
655                 ast_test_status_update(test, "%s failed to be created. Success was expected. Test failed.\n", cur_lot_name);
656                 failed = 1;
657                 goto cleanup;
658         }
659
660         cur_lot_name = "unit_tests_res_parking_test_lot_success2";
661         expect_success2 = generate_test_parking_lot(cur_lot_name,
662                 601, 605, "600", "unit_test_res_parking_create_lot_con", /* no overlap due to different extensions and ranges */
663                 test);
664         if (!expect_success2) {
665                 ast_test_status_update(test, "%s failed to be created. Success was expected. Test failed.\n", cur_lot_name);
666                 failed = 1;
667                 goto cleanup;
668         }
669
670         cur_lot_name = "unit_tests_res_parking_test_lot_success3";
671         expect_success3 = generate_test_parking_lot(cur_lot_name,
672                 704, 706, "testsuccess3", "unit_test_res_parking_create_lot_con", /* no overlap because the parking spaces start 1 above existing ranges */
673                 test);
674         if (!expect_success3) {
675                 ast_test_status_update(test, "%s failed to be created. Success was expected. Test failed.\n", cur_lot_name);
676                 failed = 1;
677                 goto cleanup;
678         }
679
680         cur_lot_name = "unit_tests_res_parking_test_lot_success4";
681         expect_success4 = generate_test_parking_lot(cur_lot_name,
682                 697, 699, "testsuccess4", "unit_test_res_parking_create_lot_con", /* no overlap because the parking spaces end 1 below existing ranges */
683                 test);
684         if (!expect_success4) {
685                 failed = 1;
686                 goto cleanup;
687         }
688
689 cleanup:
690         if (base_lot && dispose_test_lot(base_lot, 1)) {
691                 ast_test_status_update(test, "Found base parking lot in container after attempted removal. Test failed.\n");
692                 failed = 1;
693         }
694
695         if (expect_fail1) {
696                 dispose_test_lot(expect_fail1, 1);
697                 failed = 1;
698         }
699
700         if (expect_fail2) {
701                 dispose_test_lot(expect_fail2, 1);
702                 failed = 1;
703         }
704
705         if (expect_fail3) {
706                 dispose_test_lot(expect_fail3, 1);
707                 failed = 1;
708         }
709
710         if (expect_fail4) {
711                 dispose_test_lot(expect_fail4, 1);
712                 failed = 1;
713         }
714
715         if (expect_success1 && dispose_test_lot(expect_success1, 1)) {
716                 ast_test_status_update(test, "Found expect_success1 parking lot in container after attempted removal. Test failed.\n");
717                 failed = 1;
718         }
719
720         if (expect_success2 && dispose_test_lot(expect_success2, 1)) {
721                 ast_test_status_update(test, "Found expect_success2 parking lot in container after attempted removal. Test failed.\n");
722                 failed = 1;
723         }
724
725         if (expect_success3 && dispose_test_lot(expect_success3, 1)) {
726                 ast_test_status_update(test, "Found expect_success3 parking lot in container after attempted removal. Test failed.\n");
727                 failed = 1;
728         }
729
730         if (expect_success4 && dispose_test_lot(expect_success4, 1)) {
731                 ast_test_status_update(test, "Found expect_success4 parking lot in container after attempted removal. Test failed.\n");
732         }
733
734         return failed ? AST_TEST_FAIL : AST_TEST_PASS;
735 }
736
737 AST_TEST_DEFINE(dynamic_parking_variables)
738 {
739         RAII_VAR(struct parking_lot *, template_lot, NULL, ao2_cleanup);
740         RAII_VAR(struct parking_lot *, dynamic_lot, NULL, ao2_cleanup);
741         RAII_VAR(struct ast_channel *, chan_alice, NULL, safe_channel_release);
742         RAII_VAR(struct parking_lot_cfg *, expected_cfg, NULL, ao2_cleanup);
743
744         int failed = 0;
745
746         switch (cmd) {
747         case TEST_INIT:
748                 info->name = "dynamic_parking_variables";
749                 info->category = TEST_CATEGORY;
750                 info->summary = "Tests whether dynamic parking lot creation respects channel variables";
751                 info->description =
752                         "Creates a template parking lot, creates a channel, sets dynamic parking variables, and then creates a parking lot for that channel";
753                 return AST_TEST_NOT_RUN;
754         case TEST_EXECUTE:
755                 break;
756         }
757
758         ast_test_status_update(test, "Creating expected configuration for dynamic parking lot\n");
759
760         expected_cfg = parking_lot_cfg_create("unit_tests_res_parking_test_lot_dynamic");
761
762         if (!expected_cfg) {
763                 ast_test_status_update(test, "Failed to create expected configuration. Test failed.\n");
764                 return AST_TEST_FAIL;
765         }
766
767         expected_cfg->parking_start = 751;
768         expected_cfg->parking_stop = 760;
769         expected_cfg->parkingtime = 10;
770         expected_cfg->comebackdialtime = 10;
771         expected_cfg->parkfindnext = 1;
772         expected_cfg->parkext_exclusive = 1;
773         ast_string_field_set(expected_cfg, parkext, "750");
774         ast_string_field_set(expected_cfg, parking_con, "unit_test_res_parking_create_lot_dynamic");
775         ast_string_field_set(expected_cfg, comebackcontext, "unit_test_res_parking_create_lot_comeback");
776
777         ast_test_status_update(test, "Creating template lot\n");
778
779         template_lot = generate_test_parking_lot(TEST_LOT_NAME, 701, 703, "700", "unit_test_res_parking_create_lot_con", test);
780
781         if (!template_lot) {
782                 ast_test_status_update(test, "Failed to generate template lot. Test failed.\n");
783                 return AST_TEST_FAIL;
784         }
785
786         ast_test_status_update(test, "Creating Alice channel to test dynamic parking lot creation.\n");
787
788         chan_alice = create_alice_channel();
789
790         if (!chan_alice) {
791                 ast_test_status_update(test, "Failed to create Alice channel. Test failed.\n");
792                 failed = 1;
793                 goto cleanup;
794         }
795
796         ast_test_status_update(test, "Setting Dynamic Parking channel variables on Alice.\n");
797
798         pbx_builtin_setvar_helper(chan_alice, "PARKINGDYNAMIC", TEST_LOT_NAME);
799         pbx_builtin_setvar_helper(chan_alice, "PARKINGLOT", "unit_test_res_parking_create_lot_dynamic");
800         pbx_builtin_setvar_helper(chan_alice, "PARKINGDYNCONTEXT", "unit_test_res_parking_create_lot_dynamic");
801         pbx_builtin_setvar_helper(chan_alice, "PARKINGDYNEXTEN", "750");
802         pbx_builtin_setvar_helper(chan_alice, "PARKINGDYNPOS", "751-760");
803
804         ast_test_status_update(test, "Generating dynamic parking lot based on Alice's channel variables.\n");
805
806         dynamic_lot = parking_create_dynamic_lot_forced("unit_tests_res_parking_test_lot_dynamic", chan_alice);
807
808         if (!dynamic_lot) {
809                 ast_test_status_update(test, "Failed to create dynamic parking lot. Test failed.\n");
810                 failed = 1;
811                 goto cleanup;
812         }
813
814         /* Check stats */
815         if (!parking_lot_cfgs_match(dynamic_lot->cfg, expected_cfg, test)) {
816                 ast_test_status_update(test, "Dynamic parking lot configuration did not match Expectations.\n");
817                 failed = 1;
818                 goto cleanup;
819         }
820
821         ast_test_status_update(test, "Dynamic parking lot created successfully and matches expectations. Test passed.\n");
822
823 cleanup:
824         if (template_lot && dispose_test_lot(template_lot, 1)) {
825                 ast_test_status_update(test, "Found template parking lot in container after attempted removal. Test failed.\n");
826                 failed = 1;
827         }
828
829         if (dynamic_lot && dispose_test_lot(dynamic_lot, 1)) {
830                 ast_test_status_update(test, "Found dynamic parking lot in container after attempted removal. Test failed.\n");
831                 failed = 1;
832         }
833
834         return failed ? AST_TEST_FAIL : AST_TEST_PASS;
835 }
836
837 #endif /* TEST_FRAMEWORK */
838
839
840 void unload_parking_tests(void)
841 {
842 /* NOOP without test framework */
843 #if defined(TEST_FRAMEWORK)
844         AST_TEST_UNREGISTER(create_lot);
845         AST_TEST_UNREGISTER(park_call);
846         AST_TEST_UNREGISTER(retrieve_call);
847         AST_TEST_UNREGISTER(park_extensions);
848         AST_TEST_UNREGISTER(extension_conflicts);
849         AST_TEST_UNREGISTER(dynamic_parking_variables);
850 #endif
851 }
852
853 int load_parking_tests(void)
854 {
855         int res = 0;
856
857 /* NOOP without test framework */
858 #if defined(TEST_FRAMEWORK)
859         res |= AST_TEST_REGISTER(create_lot);
860         res |= AST_TEST_REGISTER(park_call);
861         res |= AST_TEST_REGISTER(retrieve_call);
862         res |= AST_TEST_REGISTER(park_extensions);
863         res |= AST_TEST_REGISTER(extension_conflicts);
864         res |= AST_TEST_REGISTER(dynamic_parking_variables);
865 #endif
866
867         return res;
868 }