Asterisk - The Open Source Telephony Project  18.5.0
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 <[email protected]>
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 <[email protected]>
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"
33 #include "asterisk/stringfields.h"
34 #include "asterisk/time.h"
35 #include "asterisk/causes.h"
36 #include "asterisk/pbx.h"
37 #include "asterisk/format_cache.h"
38 
39 #if defined(TEST_FRAMEWORK)
40 
41 #define TEST_CATEGORY "/res/parking/"
42 
43 #define CHANNEL_TECH_NAME "ParkingTestChannel"
44 
45 static 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 
52 static int parking_test_write(struct ast_channel *chan, struct ast_frame *frame)
53 {
54  return 0;
55 }
56 
57 static struct ast_frame *parking_test_read(struct ast_channel *chan)
58 {
59  return &ast_null_frame;
60 }
61 
62 static 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 */
70 static 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 */
91 static struct ast_channel *create_alice_channel(void)
92 {
93  struct ast_channel *alice = ast_channel_alloc(0, AST_STATE_DOWN,
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 */
117 static 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 
124 static void safe_channel_release(struct ast_channel *chan)
125 {
126  if (!chan) {
127  return;
128  }
129  ast_channel_release(chan);
130 }
131 
132 static 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 
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)
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 
173 static 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 
189 AST_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 
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 
234 AST_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 
269  ast_channel_state_set(chan_alice, AST_STATE_UP);
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 
286  do_sleep(&to_sleep);
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 
301 static 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 
326 static 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 
376 AST_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 
420  ast_channel_state_set(chan_alice, AST_STATE_UP);
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 
437  do_sleep(&to_sleep);
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 
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 
471 static 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 
524 AST_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 
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 
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 
570 AST_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 
687 cleanup:
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 
735 AST_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 
821 cleanup:
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 }
static struct ast_channel * create_alice_channel(void)
Create a test_cdr_chan_tech for Alice.
Definition: parking_tests.c:91
Main Channel structure associated with a channel.
const char *const type
Definition: channel.h:630
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&#39;s own link...
Definition: pbx.c:237
unsigned int comebackdialtime
Definition: res_parking.h:70
static int parking_test_write(struct ast_channel *chan, struct ast_frame *frame)
Definition: parking_tests.c:52
void ast_channel_set_writeformat(struct ast_channel *chan, struct ast_format *format)
static void safe_channel_release(struct ast_channel *chan)
static struct ast_frame * parking_test_read(struct ast_channel *chan)
Definition: parking_tests.c:57
Time-related functions and macros.
struct ast_party_name name
Subscriber name.
Definition: channel.h:341
void ast_channel_hangupcause_set(struct ast_channel *chan, int value)
struct ast_bridge * parking_bridge
Definition: res_parking.h:94
struct ast_channel * ast_channel_release(struct ast_channel *chan)
Unlink and release reference to a channel.
Definition: channel.c:1584
void ast_channel_set_rawwriteformat(struct ast_channel *chan, struct ast_format *format)
struct ast_format * ast_format_ulaw
Built-in cached ulaw format.
Definition: format_cache.c:86
const char * ast_get_extension_app(struct ast_exten *e)
Definition: pbx.c:8596
int load_parking_tests(void)
Register parking unit tests.
unsigned int parkingtime
Definition: res_parking.h:69
#define TEST_LOT_NAME
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:7459
unsigned int time_limit
Definition: res_parking.h:110
Test Framework API.
#define AST_TEST_REGISTER(cb)
Definition: test.h:127
char * str
Subscriber name (Malloced)
Definition: channel.h:265
const ast_string_field comebackcontext
Definition: res_parking.h:89
static void do_sleep(struct timespec *to_sleep)
static int check_retrieve_call_extensions(struct ast_test *test, int expected)
#define NULL
Definition: resample.c:96
static struct timespec to_sleep
A 1 second sleep.
Definition: test_cel.c:85
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.
Definition: res_parking.c:758
Utility functions.
void ast_channel_tech_set(struct ast_channel *chan, const struct ast_channel_tech *value)
static const struct ast_party_caller alice_callerid
Definition: parking_tests.c:45
#define TEST_CATEGORY
Definition: parking_tests.c:41
struct ast_party_id id
Caller party ID.
Definition: channel.h:421
#define ast_log
Definition: astobj2.c:42
void ast_channel_set_rawreadformat(struct ast_channel *chan, struct ast_format *format)
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:1924
const ast_string_field parking_con
Definition: res_parking.h:89
static int parked_users_match(const struct parked_user *actual, const struct parked_user *expected, struct ast_test *test)
AST_TEST_DEFINE(create_lot)
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...
#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:911
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
void ast_channel_nativeformats_set(struct ast_channel *chan, struct ast_format_cap *value)
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
char * parker_dial_string
Definition: res_parking.h:109
struct parking_lot_cfg * parking_lot_cfg_create(const char *cat)
Create an empty parking lot configuration structure useful for unit tests.
Definition: res_parking.c:481
static int dispose_test_lot(struct parking_lot *test_lot, int expect_destruction)
Caller Party information.
Definition: channel.h:419
int parking_space
Definition: res_parking.h:107
#define ao2_ref(o, delta)
Definition: astobj2.h:464
void ast_channel_set_readformat(struct ast_channel *chan, struct ast_format *format)
#define ast_format_cap_append(cap, format, framing)
Definition: format_cap.h:103
#define ast_format_cap_alloc(flags)
Definition: format_cap.h:52
Structure to describe a channel "technology", ie a channel driver See for examples: ...
Definition: channel.h:629
enum park_call_resolution resolution
Definition: res_parking.h:112
Core PBX routines and definitions.
#define AST_CAUSE_NORMAL
Definition: causes.h:150
#define CHANNEL_TECH_NAME
Definition: parking_tests.c:43
Structure that contains information about a bridge.
Definition: bridge.h:357
#define LOG_ERROR
Definition: logger.h:285
Format capabilities structure, holds formats + preference order + etc.
Definition: format_cap.c:54
static int set_test_formats(struct ast_channel *chan)
Set ulaw format on the channel.
Definition: parking_tests.c:70
#define AST_TEST_UNREGISTER(cb)
Definition: test.h:128
def info(msg)
int errno
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:868
int ast_bridge_depart(struct ast_channel *chan)
Depart a channel from a bridge.
Definition: bridge.c:1952
void unload_parking_tests(void)
Unregister parking unit tests.
static int parking_lot_cfgs_match(const struct parking_lot_cfg *actual, const struct parking_lot_cfg *expected, struct ast_test *test)
#define ast_channel_unlock(chan)
Definition: channel.h:2946
static const char name[]
Definition: cdr_mysql.c:74
static void test_cleanup(void)
Definition: test.c:1211
unsigned int parkfindnext
Definition: res_parking.h:71
int extens
Definition: ael_main.c:93
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition: channel.c:2548
int stacklen
Definition: extconf.h:238
const ast_string_field name
Definition: res_parking.h:100
static void * cleanup(void *unused)
Definition: pbx_realtime.c:124
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
Definition: main/frame.c:79
enum parking_lot_modes mode
Definition: res_parking.h:97
Definition: test.c:65
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
const ast_string_field parkext
Definition: res_parking.h:89
const char * ast_channel_name(const struct ast_channel *chan)
void ast_channel_state_set(struct ast_channel *chan, enum ast_channel_state)
Data structure associated with a single frame of data.
Internal Asterisk hangup causes.
static struct ast_channel * hangup_channel(struct ast_channel *chan, int hangup_cause)
Hang up a test channel safely.
struct parking_lot * parking_lot_find_by_name(const char *lot_name)
Find a parking lot based on its name.
Definition: res_parking.c:601
Call Parking Resource Internal API.
struct parking_lot * parking_create_dynamic_lot_forced(const char *name, struct ast_channel *chan)
Create a dynamic parking lot without respect to whether they are enabled by configuration.
Definition: res_parking.c:1064
#define ast_channel_alloc(needqueue, state, cid_num, cid_name, acctcode, exten, context, assignedids, requestor, amaflag,...)
Create a channel structure.
Definition: channel.h:1259
Asterisk module definitions.
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
unsigned int parkext_exclusive
Definition: res_parking.h:72
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)
Media Format Cache API.
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:514
static const struct ast_channel_tech parking_test_tech
Definition: parking_tests.c:62