test_pbx.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  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. #include <signal.h>
  37. /*!
  38. * If we determine that we really need
  39. * to be able to register more than 10
  40. * priorities for a single extension, then
  41. * fine, we can do that later.
  42. */
  43. #define MAX_PRIORITIES 10
  44. /*!
  45. * \brief an extension to add to our context
  46. */
  47. struct exten_info {
  48. /*!
  49. * \brief Context
  50. *
  51. * \details
  52. * The extension specified will be added to
  53. * this context when it is created.
  54. */
  55. const char *context;
  56. /*!
  57. * \brief Extension pattern
  58. *
  59. * \details
  60. * The extension pattern to use. This can be
  61. * anything you would normally find in a dialplan,
  62. * such as "1000" or "NXXNXXX" or whatever you
  63. * wish it to be. If, however, you want a CID match
  64. * to be part of the extension, do not include that
  65. * here.
  66. */
  67. const char *exten;
  68. /*!
  69. * \brief CID match
  70. *
  71. * \details
  72. * If your extension requires a specific caller ID in
  73. * order to match, place that in this field. Note that
  74. * a NULL and an empty CID match are two very different
  75. * things. If you want no CID match, leave this NULL. If
  76. * you want to explicitly match a blank CID, then put
  77. * an empty string here.
  78. */
  79. const char *cid;
  80. /*!
  81. * \brief Number of priorities
  82. *
  83. * \details
  84. * Tell the number of priorities to register for this
  85. * extension. All priorities registered will just have a
  86. * Noop application with the extension pattern as its
  87. * data.
  88. */
  89. const int num_priorities;
  90. /*!
  91. * \brief The priorities to register
  92. *
  93. * \details
  94. * In most cases, when registering multiple priorities for
  95. * an extension, we'll be starting at priority 1 and going
  96. * sequentially until we've read num_priorities. However,
  97. * for some tests, it may be beneficial to start at a higher
  98. * priority or skip certain priorities. This is why you have
  99. * the freedom here to specify which priorities to register
  100. * for the extension.
  101. */
  102. const int priorities[MAX_PRIORITIES];
  103. };
  104. struct pbx_test_pattern {
  105. /*!
  106. * \brief Test context
  107. *
  108. * \details
  109. * This is the context to look in for a specific extension.
  110. */
  111. const char *context;
  112. /*!
  113. * \brief Test extension number
  114. *
  115. * \details
  116. * This should be in the form of a specific number or string.
  117. * For instance, if you were trying to match an extension defined
  118. * with the pattern "_2." you might have as the test_exten one of
  119. * "2000" , "2legit2quit" or some other specific match for the pattern.
  120. */
  121. const char *test_exten;
  122. /*!
  123. * \brief Test CID match
  124. *
  125. * \details
  126. * If a specific CID match is required for pattern matching, then specify
  127. * it in this parameter. Remember that a NULL CID and an empty CID are
  128. * interpreted differently. For no CID match, leave this NULL. If you wish
  129. * to explicitly match an empty CID, then use an empty string here.
  130. */
  131. const char *test_cid;
  132. /*!
  133. * \brief The priority to find
  134. */
  135. const int priority;
  136. /*!
  137. * \brief Expected extension match.
  138. *
  139. * \details
  140. * This struct corresponds to an extension that was previously
  141. * added to our test context. Once we have used all the above data
  142. * to find an extension in the dialplan. We compare the data from that
  143. * extension to the data that we have stored in this structure to be
  144. * sure that what was matched was what we expected to match.
  145. */
  146. const struct exten_info *exten;
  147. };
  148. static int test_exten(const struct pbx_test_pattern *test_pattern, struct ast_test *test, int new_engine)
  149. {
  150. struct pbx_find_info pfi = { { 0 }, };
  151. struct ast_exten *exten;
  152. if (!(exten = pbx_find_extension(NULL, NULL, &pfi, test_pattern->context,
  153. test_pattern->test_exten, test_pattern->priority, NULL,
  154. test_pattern->test_cid, E_MATCH))) {
  155. ast_test_status_update(test, "Cannot find extension %s in context %s with the %s pattern match engine. "
  156. "Test failed.\n", test_pattern->test_exten, test_pattern->context, (new_engine ? "new" : "old"));
  157. return -1;
  158. }
  159. if (strcmp(ast_get_extension_name(exten), test_pattern->exten->exten)) {
  160. ast_test_status_update(test, "Expected extension %s but got extension %s instead with the %s pattern match engine. "
  161. "Test failed.\n", test_pattern->exten->exten, ast_get_extension_name(exten), (new_engine ? "new" : "old"));
  162. return -1;
  163. }
  164. if (test_pattern->test_cid && strcmp(ast_get_extension_cidmatch(exten), test_pattern->test_cid)) {
  165. ast_test_status_update(test, "Expected CID match %s but got CID match %s instead with the %s pattern match engine. "
  166. "Test failed.\n", test_pattern->exten->cid, ast_get_extension_cidmatch(exten), (new_engine ? "new" : "old"));
  167. return -1;
  168. }
  169. if (!ast_canmatch_extension(NULL, test_pattern->context, test_pattern->test_exten,
  170. test_pattern->priority, test_pattern->test_cid)) {
  171. ast_test_status_update(test, "Partial match failed for extension %s in context %s with the %s pattern match engine. "
  172. "Test failed.\n", test_pattern->test_exten, test_pattern->context, (new_engine ? "new" : "old"));
  173. return -1;
  174. }
  175. ast_test_status_update(test, "Successfully matched %s to exten %s in context %s with the %s pattern match engine\n",
  176. test_pattern->test_exten, test_pattern->exten->exten, test_pattern->context, (new_engine ? "new" : "old"));
  177. return 0;
  178. }
  179. AST_TEST_DEFINE(pattern_match_test)
  180. {
  181. static const char registrar[] = "test_pbx";
  182. enum ast_test_result_state res = AST_TEST_PASS;
  183. static const char TEST_PATTERN[] = "test_pattern";
  184. static const char TEST_PATTERN_INCLUDE[] = "test_pattern_include";
  185. int i, j;
  186. /* The array of contexts to register for our test.
  187. * To add more contexts, just add more rows to this array.
  188. */
  189. struct {
  190. const char * context_string;
  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 (!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. ast_context_destroy(NULL, registrar);
  302. return res;
  303. }
  304. AST_TEST_DEFINE(segv)
  305. {
  306. switch (cmd) {
  307. case TEST_INIT:
  308. info->name = "RAISE_SEGV";
  309. info->category = "/DO_NOT_RUN/";
  310. info->summary = "RAISES SEGV!!! (will only be run if explicitly called)";
  311. info->description = "RAISES SEGV!!! (will only be run if explicitly called). "
  312. "This test is mainly used for testing CI and tool failure scenarios.";
  313. info->explicit_only = 1;
  314. return AST_TEST_NOT_RUN;
  315. case TEST_EXECUTE:
  316. break;
  317. }
  318. raise(SIGSEGV);
  319. return AST_TEST_FAIL;
  320. }
  321. AST_TEST_DEFINE(call_assert)
  322. {
  323. switch (cmd) {
  324. case TEST_INIT:
  325. info->name = "CALL_ASSERT";
  326. info->category = "/DO_NOT_RUN/";
  327. info->summary = "Calls ast_asert()!!! (will only be run if explicitly called)";
  328. info->description = "Calls ast_asert()!!! (will only be run if explicitly called). "
  329. "This test is mainly used for testing CI and tool failure scenarios.";
  330. info->explicit_only = 1;
  331. return AST_TEST_NOT_RUN;
  332. case TEST_EXECUTE:
  333. break;
  334. }
  335. ast_assert(0);
  336. return AST_TEST_PASS;
  337. }
  338. AST_TEST_DEFINE(call_backtrace)
  339. {
  340. switch (cmd) {
  341. case TEST_INIT:
  342. info->name = "CALL_BACKTRACE";
  343. info->category = "/DO_NOT_RUN/";
  344. info->summary = "Calls ast_log_backtrace()!!! (will only be run if explicitly called)";
  345. info->description = "Calls ast_log_backtrace()!!! (will only be run if explicitly called). "
  346. "This test is mainly used for testing CI and tool failure scenarios.";
  347. info->explicit_only = 1;
  348. return AST_TEST_NOT_RUN;
  349. case TEST_EXECUTE:
  350. break;
  351. }
  352. ast_log_backtrace();
  353. return AST_TEST_PASS;
  354. }
  355. static int unload_module(void)
  356. {
  357. AST_TEST_UNREGISTER(call_backtrace);
  358. AST_TEST_UNREGISTER(call_assert);
  359. AST_TEST_UNREGISTER(segv);
  360. AST_TEST_UNREGISTER(pattern_match_test);
  361. return 0;
  362. }
  363. static int load_module(void)
  364. {
  365. AST_TEST_REGISTER(pattern_match_test);
  366. AST_TEST_REGISTER(segv);
  367. AST_TEST_REGISTER(call_assert);
  368. AST_TEST_REGISTER(call_backtrace);
  369. return AST_MODULE_LOAD_SUCCESS;
  370. }
  371. AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "PBX test module");