test_pbx.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  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>core</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, int new_engine)
  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 with the %s pattern match engine. "
  155. "Test failed.\n", test_pattern->test_exten, test_pattern->context, (new_engine ? "new" : "old"));
  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 with the %s pattern match engine. "
  160. "Test failed.\n", test_pattern->exten->exten, ast_get_extension_name(exten), (new_engine ? "new" : "old"));
  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 with the %s pattern match engine. "
  165. "Test failed.\n", test_pattern->exten->cid, ast_get_extension_cidmatch(exten), (new_engine ? "new" : "old"));
  166. return -1;
  167. }
  168. if (!ast_canmatch_extension(NULL, test_pattern->context, test_pattern->test_exten,
  169. test_pattern->priority, test_pattern->test_cid)) {
  170. ast_test_status_update(test, "Partial match failed for extension %s in context %s with the %s pattern match engine. "
  171. "Test failed.\n", test_pattern->test_exten, test_pattern->context, (new_engine ? "new" : "old"));
  172. return -1;
  173. }
  174. ast_test_status_update(test, "Successfully matched %s to exten %s in context %s with the %s pattern match engine\n",
  175. test_pattern->test_exten, test_pattern->exten->exten, test_pattern->context, (new_engine ? "new" : "old"));
  176. return 0;
  177. }
  178. AST_TEST_DEFINE(pattern_match_test)
  179. {
  180. static const char registrar[] = "test_pbx";
  181. enum ast_test_result_state res = AST_TEST_PASS;
  182. static const char TEST_PATTERN[] = "test_pattern";
  183. static const char TEST_PATTERN_INCLUDE[] = "test_pattern_include";
  184. int i, j;
  185. /* The array of contexts to register for our test.
  186. * To add more contexts, just add more rows to this array.
  187. */
  188. struct {
  189. const char * context_string;
  190. struct ast_context *context;
  191. } contexts[] = {
  192. { TEST_PATTERN, },
  193. { TEST_PATTERN_INCLUDE, },
  194. };
  195. /*
  196. * Map to indicate which contexts should be included inside
  197. * other contexts. The first context listed will include
  198. * the second context listed.
  199. *
  200. * To add more inclusions, add new rows to this array.
  201. */
  202. const struct {
  203. const char *outer_context;
  204. const char *inner_context;
  205. } context_includes[] = {
  206. { TEST_PATTERN, TEST_PATTERN_INCLUDE },
  207. };
  208. /* The array of extensions to add to our test context.
  209. * For more information about the individual fields, see
  210. * the doxygen for struct exten_info.
  211. *
  212. * To add new extensions to the test, simply add new rows
  213. * to this array. All extensions will automatically be
  214. * added when the test is run.
  215. */
  216. const struct exten_info extens[] = {
  217. [0] = { TEST_PATTERN, "_2.", NULL, 1, { 1 } },
  218. [1] = { TEST_PATTERN, "2000", NULL, 1, { 1 } },
  219. [2] = { TEST_PATTERN_INCLUDE, "2000", NULL, 1, { 2 } },
  220. };
  221. /* This array contains our test material. See the doxygen
  222. * for struct pbx_test_pattern for more information on each
  223. * component.
  224. *
  225. * To add more test cases, add more lines to this array. Each
  226. * case will be tested automatically when the test is run.
  227. */
  228. const struct pbx_test_pattern tests[] = {
  229. { TEST_PATTERN, "200", NULL, 1, &extens[0] },
  230. { TEST_PATTERN, "2000", NULL, 1, &extens[1] },
  231. { TEST_PATTERN, "2000", NULL, 2, &extens[2] },
  232. { TEST_PATTERN_INCLUDE, "2000", NULL, 2, &extens[2] },
  233. };
  234. switch (cmd) {
  235. case TEST_INIT:
  236. info->name = "pattern_match_test";
  237. info->category = "/main/pbx/";
  238. info->summary = "Test pattern matching";
  239. info->description = "Create a context with a bunch of extensions within. Then attempt\n"
  240. "to match some strings to the extensions.";
  241. return AST_TEST_NOT_RUN;
  242. case TEST_EXECUTE:
  243. break;
  244. }
  245. /* Step one is to build the dialplan.
  246. *
  247. * We iterate first through the contexts array to build
  248. * all the contexts we'll need. Then, we iterate over the
  249. * extens array to add all the extensions to the appropriate
  250. * contexts.
  251. */
  252. for (i = 0; i < ARRAY_LEN(contexts); ++i) {
  253. if (!(contexts[i].context = ast_context_find_or_create(NULL, NULL, contexts[i].context_string, registrar))) {
  254. ast_test_status_update(test, "Failed to create context %s\n", contexts[i].context_string);
  255. res = AST_TEST_FAIL;
  256. goto cleanup;
  257. }
  258. }
  259. for (i = 0; i < ARRAY_LEN(context_includes); ++i) {
  260. if (ast_context_add_include(context_includes[i].outer_context,
  261. context_includes[i].inner_context, registrar)) {
  262. ast_test_status_update(test, "Failed to include context %s inside context %s\n",
  263. context_includes[i].inner_context, context_includes[i].outer_context);
  264. res = AST_TEST_FAIL;
  265. goto cleanup;
  266. }
  267. }
  268. for (i = 0; i < ARRAY_LEN(extens); ++i) {
  269. int priority;
  270. if (extens[i].num_priorities > MAX_PRIORITIES) {
  271. ast_test_status_update(test, "Invalid number of priorities specified for extension %s."
  272. "Max is %d, but we requested %d. Test failed\n",
  273. extens[i].exten, MAX_PRIORITIES, extens[i].num_priorities);
  274. res = AST_TEST_FAIL;
  275. goto cleanup;
  276. }
  277. for (priority = 0; priority < extens[i].num_priorities; ++priority) {
  278. if (ast_add_extension(extens[i].context, 0, extens[i].exten, extens[i].priorities[priority],
  279. NULL, extens[i].cid, "Noop", (void *) extens[i].exten, NULL, registrar)) {
  280. ast_test_status_update(test, "Failed to add extension %s, priority %d, to context %s."
  281. "Test failed\n", extens[i].exten, extens[i].priorities[priority], extens[i].context);
  282. res = AST_TEST_FAIL;
  283. goto cleanup;
  284. }
  285. }
  286. }
  287. /* At this stage, the dialplan is built. Now we iterate over
  288. * the tests array to attempt to find each of the specified
  289. * extensions with the old and new pattern matching engines.
  290. */
  291. for (j = 0; j < 2; j++) {
  292. pbx_set_extenpatternmatchnew(j);
  293. for (i = 0; i < ARRAY_LEN(tests); ++i) {
  294. if (test_exten(&tests[i], test, j)) {
  295. res = AST_TEST_FAIL;
  296. break;
  297. }
  298. }
  299. }
  300. cleanup:
  301. for (i = 0; i < ARRAY_LEN(contexts); ++i) {
  302. if (contexts[i].context) {
  303. ast_context_destroy(contexts[i].context, registrar);
  304. }
  305. }
  306. return res;
  307. }
  308. static int unload_module(void)
  309. {
  310. AST_TEST_UNREGISTER(pattern_match_test);
  311. return 0;
  312. }
  313. static int load_module(void)
  314. {
  315. AST_TEST_REGISTER(pattern_match_test);
  316. return AST_MODULE_LOAD_SUCCESS;
  317. }
  318. AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "PBX test module");