test_pbx.c 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. /*
  2. * Asterisk -- An open source telephony toolkit.
  3. *
  4. * Copyright (C) 2010, Digium, Inc.
  5. *
  6. * Mark Michelson <mmichelson@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. /*! \file
  19. *
  20. * \brief PBX Tests
  21. *
  22. * \author Mark Michelson <mmichelson@digium.com>
  23. *
  24. * This module will run some PBX tests.
  25. * \ingroup tests
  26. */
  27. /*** MODULEINFO
  28. <depend>TEST_FRAMEWORK</depend>
  29. <support_level>extended</support_level>
  30. ***/
  31. #include "asterisk.h"
  32. ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
  33. #include "asterisk/module.h"
  34. #include "asterisk/pbx.h"
  35. #include "asterisk/test.h"
  36. /*!
  37. * If we determine that we really need
  38. * to be able to register more than 10
  39. * priorities for a single extension, then
  40. * fine, we can do that later.
  41. */
  42. #define MAX_PRIORITIES 10
  43. /*!
  44. * \brief an extension to add to our context
  45. */
  46. struct exten_info {
  47. /*!
  48. * \brief Context
  49. *
  50. * \details
  51. * The extension specified will be added to
  52. * this context when it is created.
  53. */
  54. const char *context;
  55. /*!
  56. * \brief Extension pattern
  57. *
  58. * \details
  59. * The extension pattern to use. This can be
  60. * anything you would normally find in a dialplan,
  61. * such as "1000" or "NXXNXXX" or whatever you
  62. * wish it to be. If, however, you want a CID match
  63. * to be part of the extension, do not include that
  64. * here.
  65. */
  66. const char *exten;
  67. /*!
  68. * \brief CID match
  69. *
  70. * \details
  71. * If your extension requires a specific caller ID in
  72. * order to match, place that in this field. Note that
  73. * a NULL and an empty CID match are two very different
  74. * things. If you want no CID match, leave this NULL. If
  75. * you want to explicitly match a blank CID, then put
  76. * an empty string here.
  77. */
  78. const char *cid;
  79. /*!
  80. * \brief Number of priorities
  81. *
  82. * \details
  83. * Tell the number of priorities to register for this
  84. * extension. All priorities registered will just have a
  85. * Noop application with the extension pattern as its
  86. * data.
  87. */
  88. const int num_priorities;
  89. /*!
  90. * \brief The priorities to register
  91. *
  92. * \details
  93. * In most cases, when registering multiple priorities for
  94. * an extension, we'll be starting at priority 1 and going
  95. * sequentially until we've read num_priorities. However,
  96. * for some tests, it may be beneficial to start at a higher
  97. * priority or skip certain priorities. This is why you have
  98. * the freedom here to specify which priorities to register
  99. * for the extension.
  100. */
  101. const int priorities[MAX_PRIORITIES];
  102. };
  103. struct pbx_test_pattern {
  104. /*!
  105. * \brief Test context
  106. *
  107. * \details
  108. * This is the context to look in for a specific extension.
  109. */
  110. const char *context;
  111. /*!
  112. * \brief Test extension number
  113. *
  114. * \details
  115. * This should be in the form of a specific number or string.
  116. * For instance, if you were trying to match an extension defined
  117. * with the pattern "_2." you might have as the test_exten one of
  118. * "2000" , "2legit2quit" or some other specific match for the pattern.
  119. */
  120. const char *test_exten;
  121. /*!
  122. * \brief Test CID match
  123. *
  124. * \details
  125. * If a specific CID match is required for pattern matching, then specify
  126. * it in this parameter. Remember that a NULL CID and an empty CID are
  127. * interpreted differently. For no CID match, leave this NULL. If you wish
  128. * to explicitly match an empty CID, then use an empty string here.
  129. */
  130. const char *test_cid;
  131. /*!
  132. * \brief The priority to find
  133. */
  134. const int priority;
  135. /*!
  136. * \brief Expected extension match.
  137. *
  138. * \details
  139. * This struct corresponds to an extension that was previously
  140. * added to our test context. Once we have used all the above data
  141. * to find an extension in the dialplan. We compare the data from that
  142. * extension to the data that we have stored in this structure to be
  143. * sure that what was matched was what we expected to match.
  144. */
  145. const struct exten_info *exten;
  146. };
  147. static int test_exten(const struct pbx_test_pattern *test_pattern, struct ast_test *test)
  148. {
  149. struct pbx_find_info pfi = { { 0 }, };
  150. struct ast_exten *exten;
  151. if (!(exten = pbx_find_extension(NULL, NULL, &pfi, test_pattern->context,
  152. test_pattern->test_exten, test_pattern->priority, NULL,
  153. test_pattern->test_cid, E_MATCH))) {
  154. ast_test_status_update(test, "Cannot find extension %s in context %s."
  155. "Test failed.\n", test_pattern->test_exten, test_pattern->context);
  156. return -1;
  157. }
  158. if (strcmp(ast_get_extension_name(exten), test_pattern->exten->exten)) {
  159. ast_test_status_update(test, "Expected extension %s but got extension %s instead."
  160. "Test failed.\n", test_pattern->exten->exten, ast_get_extension_name(exten));
  161. return -1;
  162. }
  163. if (test_pattern->test_cid && strcmp(ast_get_extension_cidmatch(exten), test_pattern->test_cid)) {
  164. ast_test_status_update(test, "Expected CID match %s but got CID match %s instead."
  165. "Test failed.\n", test_pattern->exten->cid, ast_get_extension_cidmatch(exten));
  166. return -1;
  167. }
  168. ast_test_status_update(test, "Successfully matched %s to exten %s in context %s\n",
  169. test_pattern->test_exten, test_pattern->exten->exten, test_pattern->context);
  170. return 0;
  171. }
  172. AST_TEST_DEFINE(pattern_match_test)
  173. {
  174. static const char registrar[] = "test_pbx";
  175. enum ast_test_result_state res = AST_TEST_PASS;
  176. static const char TEST_PATTERN[] = "test_pattern";
  177. static const char TEST_PATTERN_INCLUDE[] = "test_pattern_include";
  178. int i;
  179. /* The array of contexts to register for our test.
  180. * To add more contexts, just add more rows to this array.
  181. */
  182. struct {
  183. const char * context_string;
  184. struct ast_context *context;
  185. } contexts[] = {
  186. { TEST_PATTERN, },
  187. { TEST_PATTERN_INCLUDE, },
  188. };
  189. /*
  190. * Map to indicate which contexts should be included inside
  191. * other contexts. The first context listed will include
  192. * the second context listed.
  193. *
  194. * To add more inclusions, add new rows to this array.
  195. */
  196. const struct {
  197. const char *outer_context;
  198. const char *inner_context;
  199. } context_includes[] = {
  200. { TEST_PATTERN, TEST_PATTERN_INCLUDE },
  201. };
  202. /* The array of extensions to add to our test context.
  203. * For more information about the individual fields, see
  204. * the doxygen for struct exten_info.
  205. *
  206. * To add new extensions to the test, simply add new rows
  207. * to this array. All extensions will automatically be
  208. * added when the test is run.
  209. */
  210. const struct exten_info extens[] = {
  211. [0] = { TEST_PATTERN, "_2.", NULL, 1, { 1 } },
  212. [1] = { TEST_PATTERN, "2000", NULL, 1, { 1 } },
  213. [2] = { TEST_PATTERN_INCLUDE, "2000", NULL, 1, { 2 } },
  214. };
  215. /* This array contains our test material. See the doxygen
  216. * for struct pbx_test_pattern for more information on each
  217. * component.
  218. *
  219. * To add more test cases, add more lines to this array. Each
  220. * case will be tested automatically when the test is run.
  221. */
  222. const struct pbx_test_pattern tests[] = {
  223. { TEST_PATTERN, "200", NULL, 1, &extens[0] },
  224. { TEST_PATTERN, "2000", NULL, 1, &extens[1] },
  225. { TEST_PATTERN, "2000", NULL, 2, &extens[2] },
  226. { TEST_PATTERN_INCLUDE, "2000", NULL, 2, &extens[2] },
  227. };
  228. switch (cmd) {
  229. case TEST_INIT:
  230. info->name = "pattern_match_test";
  231. info->category = "/main/pbx/";
  232. info->summary = "Test pattern matching";
  233. info->description = "Create a context with a bunch of extensions within. Then attempt\n"
  234. "to match some strings to the extensions.";
  235. return AST_TEST_NOT_RUN;
  236. case TEST_EXECUTE:
  237. break;
  238. }
  239. /* Step one is to build the dialplan.
  240. *
  241. * We iterate first through the contexts array to build
  242. * all the contexts we'll need. Then, we iterate over the
  243. * extens array to add all the extensions to the appropriate
  244. * contexts.
  245. */
  246. for (i = 0; i < ARRAY_LEN(contexts); ++i) {
  247. if (!(contexts[i].context = ast_context_find_or_create(NULL, NULL, contexts[i].context_string, registrar))) {
  248. ast_test_status_update(test, "Failed to create context %s\n", contexts[i].context_string);
  249. res = AST_TEST_FAIL;
  250. goto cleanup;
  251. }
  252. }
  253. for (i = 0; i < ARRAY_LEN(context_includes); ++i) {
  254. if (ast_context_add_include(context_includes[i].outer_context,
  255. context_includes[i].inner_context, registrar)) {
  256. ast_test_status_update(test, "Failed to include context %s inside context %s\n",
  257. context_includes[i].inner_context, context_includes[i].outer_context);
  258. res = AST_TEST_FAIL;
  259. goto cleanup;
  260. }
  261. }
  262. for (i = 0; i < ARRAY_LEN(extens); ++i) {
  263. int priority;
  264. if (extens[i].num_priorities > MAX_PRIORITIES) {
  265. ast_test_status_update(test, "Invalid number of priorities specified for extension %s."
  266. "Max is %d, but we requested %d. Test failed\n",
  267. extens[i].exten, MAX_PRIORITIES, extens[i].num_priorities);
  268. res = AST_TEST_FAIL;
  269. goto cleanup;
  270. }
  271. for (priority = 0; priority < extens[i].num_priorities; ++priority) {
  272. if (ast_add_extension(extens[i].context, 0, extens[i].exten, extens[i].priorities[priority],
  273. NULL, extens[i].cid, "Noop", (void *) extens[i].exten, NULL, registrar)) {
  274. ast_test_status_update(test, "Failed to add extension %s, priority %d, to context %s."
  275. "Test failed\n", extens[i].exten, extens[i].priorities[priority], extens[i].context);
  276. res = AST_TEST_FAIL;
  277. goto cleanup;
  278. }
  279. }
  280. }
  281. /* At this stage, the dialplan is built. Now we iterate over
  282. * the tests array to attempt to find each of the specified
  283. * extensions.
  284. */
  285. for (i = 0; i < ARRAY_LEN(tests); ++i) {
  286. if (test_exten(&tests[i], test)) {
  287. res = AST_TEST_FAIL;
  288. break;
  289. }
  290. }
  291. cleanup:
  292. for (i = 0; i < ARRAY_LEN(contexts); ++i) {
  293. if (contexts[i].context) {
  294. ast_context_destroy(contexts[i].context, registrar);
  295. }
  296. }
  297. return res;
  298. }
  299. static int unload_module(void)
  300. {
  301. AST_TEST_UNREGISTER(pattern_match_test);
  302. return 0;
  303. }
  304. static int load_module(void)
  305. {
  306. AST_TEST_REGISTER(pattern_match_test);
  307. return AST_MODULE_LOAD_SUCCESS;
  308. }
  309. AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "PBX test module");