Asterisk - The Open Source Telephony Project  18.5.0
test_devicestate.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2010, Digium, Inc.
5  *
6  * David Vossel <[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 /*!
20  * \file
21  * \brief Device State Test Module
22  *
23  * \author David Vossel <[email protected]>
24  *
25  * \ingroup tests
26  */
27 
28 /*** MODULEINFO
29  <depend>TEST_FRAMEWORK</depend>
30  <support_level>core</support_level>
31  ***/
32 
33 #include "asterisk.h"
34 
35 #include "asterisk/utils.h"
36 #include "asterisk/module.h"
37 #include "asterisk/test.h"
38 #include "asterisk/devicestate.h"
39 #include "asterisk/pbx.h"
41 #include "asterisk/vector.h"
42 
43 #define UNIT_TEST_DEVICE_IDENTIFIER "unit_test_device_identifier"
44 
45 #define DEVICE_STATE_CHANNEL_TYPE "TestDeviceState"
46 
47 #define DEVSTATE_PROVIDER "TestDevState"
48 
49 #define DEVSTATE_PROVIDER_LC "testdevstate"
50 
51 #define DEVSTATE_PROVIDER_LEN 12
52 
53 /*! \brief Used to assign an increasing integer to channel name */
54 static unsigned int chan_idx;
55 
56 /* These arrays are the result of the 'core show device2extenstate' output. */
57 static int combined_results[] = {
139 };
140 
141 static int exten_results[] = {
149  AST_EXTENSION_INUSE | AST_EXTENSION_RINGING,
158  AST_EXTENSION_INUSE | AST_EXTENSION_RINGING,
166  AST_EXTENSION_INUSE | AST_EXTENSION_RINGING,
167  AST_EXTENSION_INUSE | AST_EXTENSION_RINGING,
175  AST_EXTENSION_INUSE | AST_EXTENSION_RINGING,
176  AST_EXTENSION_INUSE | AST_EXTENSION_RINGING,
185  AST_EXTENSION_INUSE | AST_EXTENSION_RINGING,
194  AST_EXTENSION_INUSE | AST_EXTENSION_RINGING,
198  AST_EXTENSION_INUSE | AST_EXTENSION_RINGING,
199  AST_EXTENSION_INUSE | AST_EXTENSION_RINGING,
203  AST_EXTENSION_INUSE | AST_EXTENSION_RINGING,
204  AST_EXTENSION_INUSE | AST_EXTENSION_RINGING,
205  AST_EXTENSION_INUSE | AST_EXTENSION_RINGING,
206  AST_EXTENSION_INUSE | AST_EXTENSION_RINGING,
207  AST_EXTENSION_INUSE | AST_EXTENSION_RINGING,
208  AST_EXTENSION_INUSE | AST_EXTENSION_RINGING,
209  AST_EXTENSION_INUSE | AST_EXTENSION_RINGING,
210  AST_EXTENSION_INUSE | AST_EXTENSION_RINGING,
211  AST_EXTENSION_INUSE | AST_EXTENSION_RINGING,
212  AST_EXTENSION_INUSE | AST_EXTENSION_RINGING,
213  AST_EXTENSION_INUSE | AST_EXTENSION_RINGING,
220  AST_EXTENSION_INUSE | AST_EXTENSION_RINGING,
221  AST_EXTENSION_INUSE | AST_EXTENSION_RINGING,
223 };
224 
225 /*! \brief Mutex for \c update_cond */
227 
228 /*! \brief Condition wait variable for device state updates */
230 
231 /*! \brief Mutext for \c channel_cb_cond */
233 
234 /*! \brief Condition wait variable for channel tech device state cb */
236 
237 /*! \brief The resulting device state updates caused by some function call */
238 static AST_VECTOR(, enum ast_device_state) result_states;
239 
240 /*! \brief The current device state for our device state provider */
242 
243 /*! \brief Clear out all recorded device states in \ref result_states */
244 static void clear_result_states(void)
245 {
247  while (AST_VECTOR_SIZE(&result_states) > 0) {
248  AST_VECTOR_REMOVE_UNORDERED(&result_states, 0);
249  }
251 }
252 
253 /*! \brief Stasis subscription callback for device state updates */
254 static void device_state_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
255 {
256  struct ast_device_state_message *payload;
257  enum ast_device_state state;
258  const char *device;
259 
261  return;
262  }
263 
264  payload = stasis_message_data(message);
265  state = payload->state;
266  device = payload->device;
267 
268  if (ast_strlen_zero(device)) {
269  return;
270  }
271 
272  /* Ignore aggregate events */
273  if (!payload->eid) {
274  return;
275  }
276 
277  if (strncasecmp(device, DEVSTATE_PROVIDER, DEVSTATE_PROVIDER_LEN)) {
278  return;
279  }
280 
282  AST_VECTOR_APPEND(&result_states, state);
285 }
286 
287 static enum ast_device_state devstate_prov_cb(const char *data)
288 {
289  return current_device_state;
290 }
291 
292 static int wait_for_device_state_updates(struct ast_test *test, int expected_updates)
293 {
294  int error;
295  struct timeval wait_now = ast_tvnow();
296  struct timespec wait_time = { .tv_sec = wait_now.tv_sec + 1, .tv_nsec = wait_now.tv_usec * 1000 };
297 
299  while (AST_VECTOR_SIZE(&result_states) != expected_updates) {
300  error = ast_cond_timedwait(&update_cond, &update_lock, &wait_time);
301  if (error == ETIMEDOUT) {
302  ast_test_status_update(test, "Test timed out while waiting for %d expected updates\n", expected_updates);
303  break;
304  }
305  }
307 
308  ast_test_status_update(test, "Received %zu of %d updates\n", AST_VECTOR_SIZE(&result_states), expected_updates);
309  return !(AST_VECTOR_SIZE(&result_states) == expected_updates);
310 }
311 
312 AST_TEST_DEFINE(device2extenstate_test)
313 {
314  int res = AST_TEST_PASS;
315  struct ast_devstate_aggregate agg;
316  enum ast_device_state i, j, combined;
318  int k = 0;
319 
320  switch (cmd) {
321  case TEST_INIT:
322  info->name = "device2extenstate_test";
323  info->category = "/main/devicestate/";
324  info->summary = "Tests combined devstate mapping and device to extension state mapping.";
325  info->description =
326  "Verifies device state aggregate results match the expected combined "
327  "devstate. Then verifies the combined devstate maps to the expected "
328  "extension state.";
329  return AST_TEST_NOT_RUN;
330  case TEST_EXECUTE:
331  break;
332  }
333 
335  ast_test_status_update(test, "Result array is %d long when it should be %d. "
336  "Something has changed, this test must be updated.\n",
337  (int) ARRAY_LEN(exten_results), (AST_DEVICE_TOTAL * AST_DEVICE_TOTAL));
338  return AST_TEST_FAIL;
339  }
340 
342  ast_test_status_update(test, "combined_results and exten_results arrays do not match in length.\n");
343  return AST_TEST_FAIL;
344  }
345 
346  for (i = 0; i < AST_DEVICE_TOTAL; i++) {
347  for (j = 0; j < AST_DEVICE_TOTAL; j++) {
351  combined = ast_devstate_aggregate_result(&agg);
352  if (combined_results[k] != combined) {
353  ast_test_status_update(test, "Expected combined dev state %s "
354  "does not match %s at combined_result[%d].\n",
356  ast_devstate2str(combined), k);
357  res = AST_TEST_FAIL;
358  }
359 
360  exten = ast_devstate_to_extenstate(combined);
361 
362  if (exten_results[k] != exten) {
363  ast_test_status_update(test, "Expected exten state %s "
364  "does not match %s at exten_result[%d]\n",
366  ast_extension_state2str(exten), k);
367  res = AST_TEST_FAIL;
368  }
369  k++;
370  }
371  }
372 
373  return res;
374 }
375 
376 struct consumer {
383 };
384 
385 static void consumer_dtor(void *obj)
386 {
387  struct consumer *consumer = obj;
388 
389  ast_cond_destroy(&consumer->out);
390 }
391 
392 static void consumer_reset(struct consumer *consumer)
393 {
394  consumer->already_out = 0;
395  consumer->event_count = 0;
396  consumer->state = AST_DEVICE_TOTAL;
397  consumer->aggregate_state = AST_DEVICE_TOTAL;
398 }
399 
400 static struct consumer *consumer_create(void)
401 {
402  struct consumer *consumer;
403 
404  consumer = ao2_alloc(sizeof(*consumer), consumer_dtor);
405  if (!consumer) {
406  return NULL;
407  }
408 
409  ast_cond_init(&consumer->out, NULL);
410  consumer_reset(consumer);
411 
412  return consumer;
413 }
414 
415 static void consumer_exec(void *data, struct stasis_subscription *sub, struct stasis_message *message)
416 {
417  struct consumer *consumer = data;
419  struct ast_device_state_message *device_state;
420 
421  if (!cache_update->new_snapshot) {
422  return;
423  }
424 
425  device_state = stasis_message_data(cache_update->new_snapshot);
426 
427  if (strcmp(device_state->device, UNIT_TEST_DEVICE_IDENTIFIER)) {
428  /* not a device state we're interested in */
429  return;
430  }
431 
432  {
433  SCOPED_AO2LOCK(lock, consumer);
434 
435  ++consumer->event_count;
436  if (device_state->eid) {
437  consumer->state = device_state->state;
438  if (consumer->sig_on_non_aggregate_state) {
439  consumer->sig_on_non_aggregate_state = 0;
440  consumer->already_out = 1;
441  ast_cond_signal(&consumer->out);
442  }
443  } else {
444  consumer->aggregate_state = device_state->state;
445  consumer->already_out = 1;
446  ast_cond_signal(&consumer->out);
447  }
448  }
449 }
450 
451 static void consumer_finalize(void *data, struct stasis_subscription *sub, struct stasis_message *message)
452 {
453  struct consumer *consumer = data;
454 
455  if (stasis_subscription_final_message(sub, message)) {
456  ao2_cleanup(consumer);
457  }
458 }
459 
460 static void consumer_wait_for(struct consumer *consumer)
461 {
462  int res;
463  struct timeval start = ast_tvnow();
464  struct timespec end = {
465  .tv_sec = start.tv_sec + 10,
466  .tv_nsec = start.tv_usec * 1000
467  };
468 
469  SCOPED_AO2LOCK(lock, consumer);
470 
471  while (!consumer->already_out) {
472  res = ast_cond_timedwait(&consumer->out, ao2_object_get_lockaddr(consumer), &end);
473  if (!res || res == ETIMEDOUT) {
474  break;
475  }
476  }
477 }
478 
479 static int remove_device_states_cb(void *obj, void *arg, int flags)
480 {
481  struct stasis_message *msg = obj;
482  struct ast_device_state_message *device_state = stasis_message_data(msg);
483 
484  if (strcmp(UNIT_TEST_DEVICE_IDENTIFIER, device_state->device)) {
485  /* Not a unit test device */
486  return 0;
487  }
488 
489  msg = stasis_cache_clear_create(msg);
490  if (msg) {
491  /* topic guaranteed to have been created by this point */
492  stasis_publish(ast_device_state_topic(device_state->device), msg);
493  }
494  ao2_cleanup(msg);
495  return 0;
496 }
497 
498 static void cache_cleanup(int unused)
499 {
500  struct ao2_container *cache_dump;
501 
502  /* remove all device states created during this test */
504  if (!cache_dump) {
505  return;
506  }
507  ao2_callback(cache_dump, 0, remove_device_states_cb, NULL);
508  ao2_cleanup(cache_dump);
509 }
510 
511 AST_TEST_DEFINE(device_state_aggregation_test)
512 {
515  RAII_VAR(struct ast_eid *, foreign_eid, NULL, ast_free);
516  RAII_VAR(int, cleanup_cache, 0, cache_cleanup);
517  RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
518  int res;
519  struct ast_device_state_message *device_state;
520 
521  switch (cmd) {
522  case TEST_INIT:
523  info->name = "device_state_aggregation_test";
524  info->category = "/main/devicestate/";
525  info->summary = "Tests message routing and aggregation through the Stasis device state system.";
526  info->description =
527  "Verifies that the device state system passes "
528  "messages appropriately, that the aggregator is "
529  "working properly, that the aggregate results match "
530  "the expected combined devstate, and that the cached "
531  "aggregate devstate is correct.";
532  return AST_TEST_NOT_RUN;
533  case TEST_EXECUTE:
534  break;
535  }
536 
537  foreign_eid = ast_malloc(sizeof(*foreign_eid));
538  ast_test_validate(test, NULL != foreign_eid);
539  memset(foreign_eid, 0xFF, sizeof(*foreign_eid));
540 
542  ast_test_validate(test, NULL != consumer);
543 
545  ast_test_validate(test, NULL != device_msg_router);
546 
547  ao2_ref(consumer, +1);
549  ast_test_validate(test, !res);
550 
552  ast_test_validate(test, !res);
553 
554  /* push local state */
556 
557  /* Check cache aggregate state immediately */
558  ao2_cleanup(msg);
560  device_state = stasis_message_data(msg);
561  ast_test_validate(test, AST_DEVICE_NOT_INUSE == device_state->state);
562 
564  ast_test_validate(test, AST_DEVICE_NOT_INUSE == consumer->state);
565  ast_test_validate(test, AST_DEVICE_NOT_INUSE == consumer->aggregate_state);
566  ast_test_validate(test, 2 == consumer->event_count);
568 
569  /* push remote state */
570  /* this will not produce a new aggregate state message since the aggregate state does not change */
573 
574  /* Check cache aggregate state immediately */
575  ao2_cleanup(msg);
577  device_state = stasis_message_data(msg);
578  ast_test_validate(test, AST_DEVICE_NOT_INUSE == device_state->state);
579 
580  /* Check for expected events. */
582  ast_test_validate(test, AST_DEVICE_NOT_INUSE == consumer->state);
583  ast_test_validate(test, AST_DEVICE_TOTAL == consumer->aggregate_state);
584  ast_test_validate(test, 1 == consumer->event_count);
586 
587  /* push remote state different from local state */
589 
590  /* Check cache aggregate state immediately */
591  ao2_cleanup(msg);
593  device_state = stasis_message_data(msg);
594  ast_test_validate(test, AST_DEVICE_INUSE == device_state->state);
595 
596  /* Check for expected events. */
598  ast_test_validate(test, AST_DEVICE_INUSE == consumer->state);
599  ast_test_validate(test, AST_DEVICE_INUSE == consumer->aggregate_state);
600  ast_test_validate(test, 2 == consumer->event_count);
602 
603  /* push local state that will cause aggregated state different from local non-aggregate state */
605 
606  /* Check cache aggregate state immediately */
607  ao2_cleanup(msg);
609  device_state = stasis_message_data(msg);
610  ast_test_validate(test, AST_DEVICE_RINGINUSE == device_state->state);
611 
612  /* Check for expected events. */
614  ast_test_validate(test, AST_DEVICE_RINGING == consumer->state);
615  ast_test_validate(test, AST_DEVICE_RINGINUSE == consumer->aggregate_state);
616  ast_test_validate(test, 2 == consumer->event_count);
618 
619  return AST_TEST_PASS;
620 }
621 
622 AST_TEST_DEFINE(devstate_prov_add)
623 {
624  switch (cmd) {
625  case TEST_INIT:
626  info->name = __func__;
627  info->category = "/main/devicestate/";
628  info->summary = "Test adding a device state provider";
629  info->description =
630  "Test that a custom device state provider can be added, and that\n"
631  "it cannot be added if already added.";
632  return AST_TEST_NOT_RUN;
633  case TEST_EXECUTE:
634  break;
635  }
636 
639  ast_test_validate(test, ast_devstate_prov_del(DEVSTATE_PROVIDER) == 0);
640 
641  return AST_TEST_PASS;
642 }
643 
644 AST_TEST_DEFINE(devstate_prov_del)
645 {
646  switch (cmd) {
647  case TEST_INIT:
648  info->name = __func__;
649  info->category = "/main/devicestate/";
650  info->summary = "Test removing a device state provider";
651  info->description =
652  "Test that a custom device state provider can be removed, and that\n"
653  "it cannot be removed if already removed.";
654  return AST_TEST_NOT_RUN;
655  case TEST_EXECUTE:
656  break;
657  }
658 
660  ast_test_validate(test, ast_devstate_prov_del(DEVSTATE_PROVIDER) == 0);
661  ast_test_validate(test, ast_devstate_prov_del(DEVSTATE_PROVIDER) != 0);
662 
663  return AST_TEST_PASS;
664 }
665 
666 AST_TEST_DEFINE(devstate_changed)
667 {
669  int i;
670  enum ast_device_state expected_results[] = {
679  };
680 
681  switch (cmd) {
682  case TEST_INIT:
683  info->name = __func__;
684  info->category = "/main/devicestate/";
685  info->summary = "Test updates coming from a device state provider";
686  info->description =
687  "This unit test checks that a custom device state provider can\n"
688  "have updates published for it. This includes both cacheable and\n"
689  "non-cacheable events. In the case of non-cacheable events, the\n"
690  "device state provider's callback function is queried for the\n"
691  "device state when AST_DEVICE_UNKNOWN is published.";
692  return AST_TEST_NOT_RUN;
693  case TEST_EXECUTE:
694  break;
695  }
696 
698 
701 
703 
712 
713  ast_test_validate(test, wait_for_device_state_updates(test, 8) == 0);
714 
715  for (i = 0; i < AST_VECTOR_SIZE(&result_states); i++) {
716  ast_test_status_update(test, "Testing update %d: actual is %d; expected is %d\n",
717  i,
718  AST_VECTOR_GET(&result_states, i),
719  expected_results[i]);
720  ast_test_validate(test, AST_VECTOR_GET(&result_states, i) == expected_results[i]);
721  }
722 
725 
726  /*
727  * Since an update of AST_DEVICE_UNKNOWN will cause a different thread to retrieve
728  * the update from the custom device state provider, check it separately from the
729  * updates above.
730  */
733  ast_test_validate(test, wait_for_device_state_updates(test, 1) == 0);
734 
735  ast_test_validate(test, AST_VECTOR_GET(&result_states, 0) == AST_DEVICE_BUSY);
736  ast_test_validate(test, ast_device_state(DEVSTATE_PROVIDER ":foo") == AST_DEVICE_BUSY);
737  ast_test_validate(test, ast_device_state(DEVSTATE_PROVIDER_LC ":foo") == AST_DEVICE_BUSY);
738 
741 
751 
752  ast_test_validate(test, wait_for_device_state_updates(test, 8) == 0);
753  for (i = 0; i < AST_VECTOR_SIZE(&result_states); i++) {
754  ast_test_status_update(test, "Testing update %d: actual is %d; expected is %d\n",
755  i,
756  AST_VECTOR_GET(&result_states, i),
757  expected_results[i]);
758  ast_test_validate(test, AST_VECTOR_GET(&result_states, i) == expected_results[i]);
759  }
760 
761  /*
762  * Check the last value in the cache. Note that this should not hit
763  * the value of current_device_state.
764  */
765  ast_test_validate(test, ast_device_state(DEVSTATE_PROVIDER ":foo") == AST_DEVICE_ONHOLD);
766  /*
767  * This will miss on the cache, as it is case sensitive. It should go
768  * hit our device state callback however.
769  */
770  ast_test_validate(test, ast_device_state(DEVSTATE_PROVIDER_LC ":foo") == AST_DEVICE_BUSY);
771 
772  /* Generally, this test can't be run twice in a row, as you can't remove an
773  * item from the cache. Hence, subsequent runs won't hit the device state provider,
774  * and will merely return the cached value.
775  *
776  * To avoid annoying errors, set the last state to BUSY here.
777  */
779 
780  ast_test_validate(test, ast_devstate_prov_del(DEVSTATE_PROVIDER) == 0);
781 
784 
785  return AST_TEST_PASS;
786 }
787 
788 AST_TEST_DEFINE(devstate_conversions)
789 {
790  switch (cmd) {
791  case TEST_INIT:
792  info->name = __func__;
793  info->category = "/main/devicestate/";
794  info->summary = "Test ast_device_state conversions";
795  info->description =
796  "Test various transformations of ast_device_state values.";
797  return AST_TEST_NOT_RUN;
798  case TEST_EXECUTE:
799  break;
800  }
801 
802  ast_test_validate(test, !strcmp(ast_devstate_str(AST_DEVICE_UNKNOWN), "UNKNOWN"));
803  ast_test_validate(test, !strcmp(ast_devstate_str(AST_DEVICE_NOT_INUSE), "NOT_INUSE"));
804  ast_test_validate(test, !strcmp(ast_devstate_str(AST_DEVICE_INUSE), "INUSE"));
805  ast_test_validate(test, !strcmp(ast_devstate_str(AST_DEVICE_BUSY), "BUSY"));
806  ast_test_validate(test, !strcmp(ast_devstate_str(AST_DEVICE_INVALID), "INVALID"));
807  ast_test_validate(test, !strcmp(ast_devstate_str(AST_DEVICE_UNAVAILABLE), "UNAVAILABLE"));
808  ast_test_validate(test, !strcmp(ast_devstate_str(AST_DEVICE_RINGING), "RINGING"));
809  ast_test_validate(test, !strcmp(ast_devstate_str(AST_DEVICE_RINGINUSE), "RINGINUSE"));
810  ast_test_validate(test, !strcmp(ast_devstate_str(AST_DEVICE_ONHOLD), "ONHOLD"));
811 
812  ast_test_validate(test, ast_devstate_val("UNKNOWN") == AST_DEVICE_UNKNOWN);
813  ast_test_validate(test, ast_devstate_val("NOT_INUSE") == AST_DEVICE_NOT_INUSE);
814  ast_test_validate(test, ast_devstate_val("INUSE") == AST_DEVICE_INUSE);
815  ast_test_validate(test, ast_devstate_val("BUSY") == AST_DEVICE_BUSY);
816  ast_test_validate(test, ast_devstate_val("INVALID") == AST_DEVICE_INVALID);
817  ast_test_validate(test, ast_devstate_val("UNAVAILABLE") == AST_DEVICE_UNAVAILABLE);
818  ast_test_validate(test, ast_devstate_val("RINGING") == AST_DEVICE_RINGING);
819  ast_test_validate(test, ast_devstate_val("RINGINUSE") == AST_DEVICE_RINGINUSE);
820  ast_test_validate(test, ast_devstate_val("ONHOLD") == AST_DEVICE_ONHOLD);
821  ast_test_validate(test, ast_devstate_val("onhold") == AST_DEVICE_ONHOLD);
822  ast_test_validate(test, ast_devstate_val("FOO") == AST_DEVICE_UNKNOWN);
823 
828  ast_test_validate(test, ast_state_chan2dev(AST_STATE_RING) == AST_DEVICE_INUSE);
830  ast_test_validate(test, ast_state_chan2dev(AST_STATE_UP) == AST_DEVICE_INUSE);
831  ast_test_validate(test, ast_state_chan2dev(AST_STATE_BUSY) == AST_DEVICE_BUSY);
834 
835  return AST_TEST_PASS;
836 }
837 
838 /*! \brief Whether or not the channel device state callback was called */
840 
841 /*! \brief Wait until the test channel driver's devicestate callback is called */
843 {
844  int error;
845  struct timeval wait_now = ast_tvnow();
846  struct timespec wait_time = { .tv_sec = wait_now.tv_sec + 1, .tv_nsec = wait_now.tv_usec * 1000 };
847 
849  while (!chan_callback_called) {
850  error = ast_cond_timedwait(&channel_cb_cond, &channel_cb_lock, &wait_time);
851  if (error == ETIMEDOUT) {
852  ast_test_status_update(test, "Test timed out while waiting channel callback\n");
853  break;
854  }
855  }
857 
858  return chan_callback_called;
859 }
860 
861 static void safe_hangup(void *object)
862 {
863  struct ast_channel *chan = object;
864 
865  if (!chan) {
866  return;
867  }
868  ast_hangup(chan);
869 }
870 
871 AST_TEST_DEFINE(devstate_channels)
872 {
873  RAII_VAR(struct ast_channel *, chan, NULL, safe_hangup);
874 
875  switch (cmd) {
876  case TEST_INIT:
877  info->name = __func__;
878  info->category = "/main/devicestate/";
879  info->summary = "Test deriving device state from a channel's state";
880  info->description =
881  "Test querying a channel's state to derive a device state.";
882  return AST_TEST_NOT_RUN;
883  case TEST_EXECUTE:
884  break;
885  }
886 
888 
889  chan = ast_channel_alloc(0, AST_STATE_RINGING, "", "", "", "s", "default",
890  NULL, NULL, 0, DEVICE_STATE_CHANNEL_TYPE "/foo-%08x",
891  (unsigned) ast_atomic_fetchadd_int((int *) &chan_idx, +1));
892  ast_test_validate(test, chan != NULL);
893 
896 
897  ast_setstate(chan, AST_STATE_UP);
898 
899  ast_test_validate(test, wait_for_channel_callback(test) == 1);
901 
903 
904  return AST_TEST_PASS;
905 }
906 
907 static int chan_test_devicestate_cb(const char *device_number)
908 {
909  /* Simply record that we were called when expected */
911 
915 
916  return AST_DEVICE_INUSE;
917 }
918 
921  .description = "Device State Unit Test Channel Driver",
922  .devicestate = chan_test_devicestate_cb,
923 };
924 
925 static int unload_module(void)
926 {
927  AST_VECTOR_FREE(&result_states);
928  ast_channel_unregister(&chan_test_devicestate);
929 
930  AST_TEST_UNREGISTER(device2extenstate_test);
931  AST_TEST_UNREGISTER(device_state_aggregation_test);
932 
933  AST_TEST_UNREGISTER(devstate_prov_add);
934  AST_TEST_UNREGISTER(devstate_prov_del);
935 
936  AST_TEST_UNREGISTER(devstate_changed);
937  AST_TEST_UNREGISTER(devstate_conversions);
938 
939  AST_TEST_UNREGISTER(devstate_channels);
940 
941  return 0;
942 }
943 
944 static int load_module(void)
945 {
946  if (AST_VECTOR_INIT(&result_states, 8) == -1) {
948  }
949 
950  if (ast_channel_register(&chan_test_devicestate)) {
951  AST_VECTOR_FREE(&result_states);
953  }
954 
955  AST_TEST_REGISTER(device_state_aggregation_test);
956  AST_TEST_REGISTER(device2extenstate_test);
957 
958  AST_TEST_REGISTER(devstate_prov_add);
959  AST_TEST_REGISTER(devstate_prov_del);
960 
961  AST_TEST_REGISTER(devstate_changed);
962  AST_TEST_REGISTER(devstate_conversions);
963 
964  AST_TEST_REGISTER(devstate_channels);
965 
967 }
968 
#define DEVICE_STATE_CHANNEL_TYPE
struct stasis_topic * ast_device_state_topic(const char *device)
Get the Stasis topic for device state messages for a specific device.
Definition: devicestate.c:683
struct ao2_container * stasis_cache_dump_all(struct stasis_cache *cache, struct stasis_message_type *type)
Dump all entity items from the cache to a subscription.
Definition: stasis_cache.c:757
#define UNIT_TEST_DEVICE_IDENTIFIER
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
Definition: vector.h:174
enum sip_cc_notify_state state
Definition: chan_sip.c:959
const char * ast_devstate2str(enum ast_device_state devstate) attribute_pure
Convert device state to text string for output.
Definition: devicestate.c:237
static char exten[AST_MAX_EXTENSION]
Definition: chan_alsa.c:118
Main Channel structure associated with a channel.
ast_device_state
Device States.
Definition: devicestate.h:52
#define AST_MODULE_INFO_STANDARD(keystr, desc)
Definition: module.h:567
ast_cond_t out
const char *const type
Definition: channel.h:630
ast_extension_states
Extension states.
Definition: pbx.h:61
Asterisk main include file. File version handling, generic pbx functions.
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
static enum ast_device_state current_device_state
The current device state for our device state provider.
static ast_mutex_t update_lock
Mutex for update_cond.
Device state management.
void ast_channel_unregister(const struct ast_channel_tech *tech)
Unregister a channel technology.
Definition: channel.c:570
#define DEVSTATE_PROVIDER
static AST_VECTOR(, enum ast_device_state) result_states
The resulting device state updates caused by some function call.
int stasis_message_router_add(struct stasis_message_router *router, struct stasis_message_type *message_type, stasis_subscription_cb callback, void *data)
Add a route to a message router.
#define ao2_callback(c, flags, cb_fn, arg)
Definition: astobj2.h:1716
enum ast_device_state state
Definition: devicestate.h:250
static unsigned int chan_idx
Used to assign an increasing integer to channel name.
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
Definition: vector.h:256
enum ast_device_state ast_parse_device_state(const char *device)
Search the Channels by Name.
Definition: devicestate.c:287
static int combined_results[]
Test Framework API.
#define AST_TEST_REGISTER(cb)
Definition: test.h:127
int ast_devstate_prov_del(const char *label)
Remove device state provider.
Definition: devicestate.c:418
static void cache_cleanup(int unused)
struct stasis_message_type * stasis_message_type(const struct stasis_message *msg)
Get the message type for a stasis_message.
static void consumer_finalize(void *data, struct stasis_subscription *sub, struct stasis_message *message)
#define AST_VECTOR_REMOVE_UNORDERED(vec, idx)
Remove an element from an unordered vector by index.
Definition: vector.h:438
#define ast_cond_init(cond, attr)
Definition: lock.h:199
struct stasis_message * stasis_cache_clear_create(struct stasis_message *message)
A message which instructs the caching topic to remove an entry from its cache.
Definition: stasis_cache.c:778
static void consumer_dtor(void *obj)
int ast_devstate_prov_add(const char *label, ast_devstate_prov_cb_type callback)
Add device state provider.
Definition: devicestate.c:391
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:150
struct stasis_message * stasis_cache_get_by_eid(struct stasis_cache *cache, struct stasis_message_type *type, const char *id, const struct ast_eid *eid)
Retrieve an item from the cache for a specific entity.
Definition: stasis_cache.c:659
#define ast_mutex_lock(a)
Definition: lock.h:187
int ast_channel_register(const struct ast_channel_tech *tech)
Register a channel technology (a new channel driver) Called by a channel module to register the kind ...
Definition: channel.c:539
static int chan_test_devicestate_cb(const char *device_number)
#define NULL
Definition: resample.c:96
#define ast_cond_signal(cond)
Definition: lock.h:201
An Entity ID is essentially a MAC address, brief and unique.
Definition: utils.h:786
int ast_atomic_fetchadd_int(volatile int *p, int v)
Atomically add v to *p and return the previous value of *p.
Definition: lock.h:755
enum ast_device_state ast_devstate_aggregate_result(struct ast_devstate_aggregate *agg)
Get the aggregate device state result.
Definition: devicestate.c:663
static ast_mutex_t channel_cb_lock
Mutext for channel_cb_cond.
#define DEVSTATE_PROVIDER_LEN
Utility functions.
static int chan_callback_called
Whether or not the channel device state callback was called.
pthread_cond_t ast_cond_t
Definition: lock.h:176
#define ast_strlen_zero(foo)
Definition: strings.h:52
int sig_on_non_aggregate_state
static struct consumer * consumer_create(void)
static int wait_for_device_state_updates(struct ast_test *test, int expected_updates)
void * ao2_object_get_lockaddr(void *obj)
Return the mutex lock address of an object.
Definition: astobj2.c:476
static void device_state_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
Stasis subscription callback for device state updates.
struct stasis_message_type * ast_device_state_message_type(void)
Get the Stasis message type for device state messages.
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Definition: vector.h:113
struct stasis_topic * ast_device_state_topic_cached(void)
Get the Stasis caching topic for device state messages.
Definition: devicestate.c:678
enum ast_device_state ast_devstate_val(const char *val)
Convert device state from text to integer value.
Definition: devicestate.c:260
#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
const struct ast_eid * eid
The EID of the server where this message originated.
Definition: devicestate.h:248
ast_mutex_t lock
Definition: app_meetme.c:1091
#define ao2_ref(o, delta)
Definition: astobj2.h:464
const char * ast_extension_state2str(int extension_state)
Return string representation of the state of an extension.
Definition: pbx.c:3126
struct stasis_message_type * stasis_cache_update_type(void)
Message type for cache update messages.
static enum ast_device_state devstate_prov_cb(const char *data)
#define ast_malloc(len)
A wrapper for malloc()
Definition: astmm.h:193
enum ast_device_state ast_state_chan2dev(enum ast_channel_state chanstate)
Convert channel state to devicestate.
Definition: devicestate.c:242
Structure to describe a channel "technology", ie a channel driver See for examples: ...
Definition: channel.h:629
Cache update message.
Definition: stasis.h:967
Core PBX routines and definitions.
#define stasis_message_router_create(topic)
#define stasis_subscribe(topic, callback, data)
Definition: stasis.h:652
static int cache_update(struct stasis_message *msg, const void *data)
Message matcher looking for cache update messages.
static void consumer_reset(struct consumer *consumer)
void ast_devstate_aggregate_add(struct ast_devstate_aggregate *agg, enum ast_device_state state)
Add a device state to the aggregate device state.
Definition: devicestate.c:636
static int remove_device_states_cb(void *obj, void *arg, int flags)
const char * ast_devstate_str(enum ast_device_state devstate) attribute_pure
Convert device state to text string that is easier to parse.
Definition: devicestate.c:255
struct stasis_message * new_snapshot
New value.
Definition: stasis.h:973
int ast_publish_device_state_full(const char *device, enum ast_device_state state, enum ast_devstate_cache cachable, struct ast_eid *eid)
Publish a device state update with EID.
Definition: devicestate.c:709
struct stasis_cache * ast_device_state_cache(void)
Backend cache for ast_device_state_topic_cached()
Definition: devicestate.c:673
static void safe_hangup(void *object)
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
#define AST_TEST_UNREGISTER(cb)
Definition: test.h:128
static int load_module(void)
def info(msg)
#define ast_cond_destroy(cond)
Definition: lock.h:200
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:411
struct stasis_topic * ast_device_state_topic_all(void)
Get the Stasis topic for device state messages.
Definition: devicestate.c:668
int stasis_subscription_final_message(struct stasis_subscription *sub, struct stasis_message *msg)
Determine whether a message is the final message to be received on a subscription.
Definition: stasis.c:1176
enum ast_extension_states ast_devstate_to_extenstate(enum ast_device_state devstate)
Map devstate to an extension state.
Definition: pbx.c:3006
void stasis_publish(struct stasis_topic *topic, struct stasis_message *message)
Publish a message to a topic&#39;s subscribers.
Definition: stasis.c:1511
#define SCOPED_AO2LOCK(varname, obj)
scoped lock specialization for ao2 mutexes.
Definition: lock.h:602
#define ast_free(a)
Definition: astmm.h:182
void ast_devstate_aggregate_init(struct ast_devstate_aggregate *agg)
Initialize aggregate device state.
Definition: devicestate.c:630
AST_TEST_DEFINE(device2extenstate_test)
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition: channel.c:2548
enum ast_device_state state
struct stasis_subscription * stasis_unsubscribe_and_join(struct stasis_subscription *subscription)
Cancel a subscription, blocking until the last message is processed.
Definition: stasis.c:1136
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
Vector container support.
#define DEVSTATE_PROVIDER_LC
static ast_cond_t channel_cb_cond
Condition wait variable for channel tech device state cb.
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:682
Definition: test.c:65
static int wait_for_channel_callback(struct ast_test *test)
Wait until the test channel driver&#39;s devicestate callback is called.
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
static void clear_result_states(void)
Clear out all recorded device states in result_states.
int ast_setstate(struct ast_channel *chan, enum ast_channel_state)
Change the state of a channel.
Definition: channel.c:7486
void stasis_message_router_unsubscribe(struct stasis_message_router *router)
Unsubscribe the router from the upstream topic.
struct stasis_forward * sub
Definition: res_corosync.c:240
static int unload_module(void)
You shouldn&#39;t care about the contents of this struct.
Definition: devicestate.h:230
enum ast_device_state aggregate_state
The structure that contains device state.
Definition: devicestate.h:240
int error(const char *format,...)
Definition: utils/frame.c:999
struct stasis_message_type * stasis_subscription_change_type(void)
Gets the message type for subscription change notices.
Generic container type.
static int exten_results[]
int ast_devstate_changed_literal(enum ast_device_state state, enum ast_devstate_cache cachable, const char *device)
Tells Asterisk the State for Device is changed.
Definition: devicestate.c:471
static void consumer_exec(void *data, struct stasis_subscription *sub, struct stasis_message *message)
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
#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.
static void consumer_wait_for(struct consumer *consumer)
#define ast_cond_timedwait(cond, mutex, time)
Definition: lock.h:204
struct ast_channel_tech chan_test_devicestate
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:611
#define AST_MUTEX_DEFINE_STATIC(mutex)
Definition: lock.h:518
#define ast_mutex_unlock(a)
Definition: lock.h:188
static ast_cond_t update_cond
Condition wait variable for device state updates.
#define ast_publish_device_state(device, state, cachable)
Publish a device state update.
Definition: devicestate.h:323