Asterisk - The Open Source Telephony Project  18.5.0
test_pbx.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  * Mark Michelson <[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 PBX Tests
22  *
23  * \author Mark Michelson <[email protected]>
24  *
25  * This module will run some PBX tests.
26  * \ingroup tests
27  */
28 
29 /*** MODULEINFO
30  <depend>TEST_FRAMEWORK</depend>
31  <support_level>core</support_level>
32  ***/
33 
34 #include "asterisk.h"
35 
36 #include "asterisk/module.h"
37 #include "asterisk/pbx.h"
38 #include "asterisk/test.h"
39 
40 #include <signal.h>
41 
42 /*!
43  * If we determine that we really need
44  * to be able to register more than 10
45  * priorities for a single extension, then
46  * fine, we can do that later.
47  */
48 #define MAX_PRIORITIES 10
49 
50 /*!
51  * \brief an extension to add to our context
52  */
53 struct exten_info {
54  /*!
55  * \brief Context
56  *
57  * \details
58  * The extension specified will be added to
59  * this context when it is created.
60  */
61  const char *context;
62  /*!
63  * \brief Extension pattern
64  *
65  * \details
66  * The extension pattern to use. This can be
67  * anything you would normally find in a dialplan,
68  * such as "1000" or "NXXNXXX" or whatever you
69  * wish it to be. If, however, you want a CID match
70  * to be part of the extension, do not include that
71  * here.
72  */
73  const char *exten;
74  /*!
75  * \brief CID match
76  *
77  * \details
78  * If your extension requires a specific caller ID in
79  * order to match, place that in this field. Note that
80  * a NULL and an empty CID match are two very different
81  * things. If you want no CID match, leave this NULL. If
82  * you want to explicitly match a blank CID, then put
83  * an empty string here.
84  */
85  const char *cid;
86  /*!
87  * \brief Number of priorities
88  *
89  * \details
90  * Tell the number of priorities to register for this
91  * extension. All priorities registered will just have a
92  * Noop application with the extension pattern as its
93  * data.
94  */
95  const int num_priorities;
96  /*!
97  * \brief The priorities to register
98  *
99  * \details
100  * In most cases, when registering multiple priorities for
101  * an extension, we'll be starting at priority 1 and going
102  * sequentially until we've read num_priorities. However,
103  * for some tests, it may be beneficial to start at a higher
104  * priority or skip certain priorities. This is why you have
105  * the freedom here to specify which priorities to register
106  * for the extension.
107  */
109 };
110 
112  /*!
113  * \brief Test context
114  *
115  * \details
116  * This is the context to look in for a specific extension.
117  */
118  const char *context;
119  /*!
120  * \brief Test extension number
121  *
122  * \details
123  * This should be in the form of a specific number or string.
124  * For instance, if you were trying to match an extension defined
125  * with the pattern "_2." you might have as the test_exten one of
126  * "2000" , "2legit2quit" or some other specific match for the pattern.
127  */
128  const char *test_exten;
129  /*!
130  * \brief Test CID match
131  *
132  * \details
133  * If a specific CID match is required for pattern matching, then specify
134  * it in this parameter. Remember that a NULL CID and an empty CID are
135  * interpreted differently. For no CID match, leave this NULL. If you wish
136  * to explicitly match an empty CID, then use an empty string here.
137  */
138  const char *test_cid;
139  /*!
140  * \brief The priority to find
141  */
142  const int priority;
143  /*!
144  * \brief Expected extension match.
145  *
146  * \details
147  * This struct corresponds to an extension that was previously
148  * added to our test context. Once we have used all the above data
149  * to find an extension in the dialplan. We compare the data from that
150  * extension to the data that we have stored in this structure to be
151  * sure that what was matched was what we expected to match.
152  */
153  const struct exten_info *exten;
154 };
155 
156 static int test_exten(const struct pbx_test_pattern *test_pattern, struct ast_test *test, int new_engine)
157 {
158  struct pbx_find_info pfi = { { 0 }, };
159  struct ast_exten *exten;
160  if (!(exten = pbx_find_extension(NULL, NULL, &pfi, test_pattern->context,
161  test_pattern->test_exten, test_pattern->priority, NULL,
162  test_pattern->test_cid, E_MATCH))) {
163  ast_test_status_update(test, "Cannot find extension %s in context %s with the %s pattern match engine. "
164  "Test failed.\n", test_pattern->test_exten, test_pattern->context, (new_engine ? "new" : "old"));
165  return -1;
166  }
167  if (strcmp(ast_get_extension_name(exten), test_pattern->exten->exten)) {
168  ast_test_status_update(test, "Expected extension %s but got extension %s instead with the %s pattern match engine. "
169  "Test failed.\n", test_pattern->exten->exten, ast_get_extension_name(exten), (new_engine ? "new" : "old"));
170  return -1;
171  }
172  if (test_pattern->test_cid && strcmp(ast_get_extension_cidmatch(exten), test_pattern->test_cid)) {
173  ast_test_status_update(test, "Expected CID match %s but got CID match %s instead with the %s pattern match engine. "
174  "Test failed.\n", test_pattern->exten->cid, ast_get_extension_cidmatch(exten), (new_engine ? "new" : "old"));
175  return -1;
176  }
177  if (!ast_canmatch_extension(NULL, test_pattern->context, test_pattern->test_exten,
178  test_pattern->priority, test_pattern->test_cid)) {
179  ast_test_status_update(test, "Partial match failed for extension %s in context %s with the %s pattern match engine. "
180  "Test failed.\n", test_pattern->test_exten, test_pattern->context, (new_engine ? "new" : "old"));
181  return -1;
182  }
183  ast_test_status_update(test, "Successfully matched %s to exten %s in context %s with the %s pattern match engine\n",
184  test_pattern->test_exten, test_pattern->exten->exten, test_pattern->context, (new_engine ? "new" : "old"));
185  return 0;
186 }
187 
188 AST_TEST_DEFINE(pattern_match_test)
189 {
190  static const char registrar[] = "test_pbx";
192  static const char TEST_PATTERN[] = "test_pattern";
193  static const char TEST_PATTERN_INCLUDE[] = "test_pattern_include";
194  int i, j;
195 
196  /* The array of contexts to register for our test.
197  * To add more contexts, just add more rows to this array.
198  */
199  struct {
200  const char * context_string;
201  } contexts[] = {
202  { TEST_PATTERN, },
203  { TEST_PATTERN_INCLUDE, },
204  };
205 
206  /*
207  * Map to indicate which contexts should be included inside
208  * other contexts. The first context listed will include
209  * the second context listed.
210  *
211  * To add more inclusions, add new rows to this array.
212  */
213  const struct {
214  const char *outer_context;
215  const char *inner_context;
216  } context_includes[] = {
217  { TEST_PATTERN, TEST_PATTERN_INCLUDE },
218  };
219 
220  /* The array of extensions to add to our test context.
221  * For more information about the individual fields, see
222  * the doxygen for struct exten_info.
223  *
224  * To add new extensions to the test, simply add new rows
225  * to this array. All extensions will automatically be
226  * added when the test is run.
227  */
228  const struct exten_info extens[] = {
229  [0] = { TEST_PATTERN, "_2.", NULL, 1, { 1 } },
230  [1] = { TEST_PATTERN, "2000", NULL, 1, { 1 } },
231  [2] = { TEST_PATTERN_INCLUDE, "2000", NULL, 1, { 2 } },
232  };
233 
234  /* This array contains our test material. See the doxygen
235  * for struct pbx_test_pattern for more information on each
236  * component.
237  *
238  * To add more test cases, add more lines to this array. Each
239  * case will be tested automatically when the test is run.
240  */
241  const struct pbx_test_pattern tests[] = {
242  { TEST_PATTERN, "200", NULL, 1, &extens[0] },
243  { TEST_PATTERN, "2000", NULL, 1, &extens[1] },
244  { TEST_PATTERN, "2000", NULL, 2, &extens[2] },
245  { TEST_PATTERN_INCLUDE, "2000", NULL, 2, &extens[2] },
246  };
247 
248  switch (cmd) {
249  case TEST_INIT:
250  info->name = "pattern_match_test";
251  info->category = "/main/pbx/";
252  info->summary = "Test pattern matching";
253  info->description = "Create a context with a bunch of extensions within. Then attempt\n"
254  "to match some strings to the extensions.";
255  return AST_TEST_NOT_RUN;
256  case TEST_EXECUTE:
257  break;
258  }
259 
260  /* Step one is to build the dialplan.
261  *
262  * We iterate first through the contexts array to build
263  * all the contexts we'll need. Then, we iterate over the
264  * extens array to add all the extensions to the appropriate
265  * contexts.
266  */
267 
268  for (i = 0; i < ARRAY_LEN(contexts); ++i) {
269  if (!ast_context_find_or_create(NULL, NULL, contexts[i].context_string, registrar)) {
270  ast_test_status_update(test, "Failed to create context %s\n", contexts[i].context_string);
271  res = AST_TEST_FAIL;
272  goto cleanup;
273  }
274  }
275 
276  for (i = 0; i < ARRAY_LEN(context_includes); ++i) {
277  if (ast_context_add_include(context_includes[i].outer_context,
278  context_includes[i].inner_context, registrar)) {
279  ast_test_status_update(test, "Failed to include context %s inside context %s\n",
280  context_includes[i].inner_context, context_includes[i].outer_context);
281  res = AST_TEST_FAIL;
282  goto cleanup;
283  }
284  }
285 
286  for (i = 0; i < ARRAY_LEN(extens); ++i) {
287  int priority;
288  if (extens[i].num_priorities > MAX_PRIORITIES) {
289  ast_test_status_update(test, "Invalid number of priorities specified for extension %s."
290  "Max is %d, but we requested %d. Test failed\n",
291  extens[i].exten, MAX_PRIORITIES, extens[i].num_priorities);
292  res = AST_TEST_FAIL;
293  goto cleanup;
294  }
295  for (priority = 0; priority < extens[i].num_priorities; ++priority) {
296  if (ast_add_extension(extens[i].context, 0, extens[i].exten, extens[i].priorities[priority],
297  NULL, extens[i].cid, "Noop", (void *) extens[i].exten, NULL, registrar)) {
298  ast_test_status_update(test, "Failed to add extension %s, priority %d, to context %s."
299  "Test failed\n", extens[i].exten, extens[i].priorities[priority], extens[i].context);
300  res = AST_TEST_FAIL;
301  goto cleanup;
302  }
303  }
304  }
305 
306  /* At this stage, the dialplan is built. Now we iterate over
307  * the tests array to attempt to find each of the specified
308  * extensions with the old and new pattern matching engines.
309  */
310  for (j = 0; j < 2; j++) {
312  for (i = 0; i < ARRAY_LEN(tests); ++i) {
313  if (test_exten(&tests[i], test, j)) {
314  res = AST_TEST_FAIL;
315  break;
316  }
317  }
318  }
319 
320 cleanup:
321  ast_context_destroy(NULL, registrar);
322 
323  return res;
324 }
325 
327 {
328  switch (cmd) {
329  case TEST_INIT:
330  info->name = "RAISE_SEGV";
331  info->category = "/DO_NOT_RUN/";
332  info->summary = "RAISES SEGV!!! (will only be run if explicitly called)";
333  info->description = "RAISES SEGV!!! (will only be run if explicitly called). "
334  "This test is mainly used for testing CI and tool failure scenarios.";
335  info->explicit_only = 1;
336  return AST_TEST_NOT_RUN;
337  case TEST_EXECUTE:
338  break;
339  }
340 
341  raise(SIGSEGV);
342 
343  return AST_TEST_FAIL;
344 }
345 
346 AST_TEST_DEFINE(call_assert)
347 {
348  switch (cmd) {
349  case TEST_INIT:
350  info->name = "CALL_ASSERT";
351  info->category = "/DO_NOT_RUN/";
352  info->summary = "Calls ast_asert()!!! (will only be run if explicitly called)";
353  info->description = "Calls ast_asert()!!! (will only be run if explicitly called). "
354  "This test is mainly used for testing CI and tool failure scenarios.";
355  info->explicit_only = 1;
356  return AST_TEST_NOT_RUN;
357  case TEST_EXECUTE:
358  break;
359  }
360 
361  ast_assert(0);
362 
363  return AST_TEST_PASS;
364 }
365 
366 AST_TEST_DEFINE(call_backtrace)
367 {
368  switch (cmd) {
369  case TEST_INIT:
370  info->name = "CALL_BACKTRACE";
371  info->category = "/DO_NOT_RUN/";
372  info->summary = "Calls ast_log_backtrace()!!! (will only be run if explicitly called)";
373  info->description = "Calls ast_log_backtrace()!!! (will only be run if explicitly called). "
374  "This test is mainly used for testing CI and tool failure scenarios.";
375  info->explicit_only = 1;
376  return AST_TEST_NOT_RUN;
377  case TEST_EXECUTE:
378  break;
379  }
380 
382 
383  return AST_TEST_PASS;
384 }
385 
386 static int unload_module(void)
387 {
388  AST_TEST_UNREGISTER(call_backtrace);
389  AST_TEST_UNREGISTER(call_assert);
390  AST_TEST_UNREGISTER(segv);
391  AST_TEST_UNREGISTER(pattern_match_test);
392  return 0;
393 }
394 
395 static int load_module(void)
396 {
397  AST_TEST_REGISTER(pattern_match_test);
398  AST_TEST_REGISTER(segv);
399  AST_TEST_REGISTER(call_assert);
400  AST_TEST_REGISTER(call_backtrace);
402 }
403 
const struct exten_info * exten
Expected extension match.
Definition: test_pbx.c:153
static int unload_module(void)
Definition: test_pbx.c:386
#define AST_MODULE_INFO_STANDARD(keystr, desc)
Definition: module.h:567
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
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
const char * cid
CID match.
Definition: test_pbx.c:85
const char * test_cid
Test CID match.
Definition: test_pbx.c:138
const char * context
Context.
Definition: test_pbx.c:61
Test Framework API.
#define AST_TEST_REGISTER(cb)
Definition: test.h:127
#define ast_assert(a)
Definition: utils.h:695
#define NULL
Definition: resample.c:96
static int load_module(void)
Definition: test_pbx.c:395
static int priority
int ast_context_add_include(const char *context, const char *include, const char *registrar)
Add a context include.
Definition: pbx.c:6706
AST_TEST_DEFINE(pattern_match_test)
Definition: test_pbx.c:188
int ast_canmatch_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
Looks for a valid matching extension.
Definition: pbx.c:4194
void ast_log_backtrace(void)
Log a backtrace of the current thread&#39;s execution stack to the Asterisk log.
Definition: logger.c:2158
#define MAX_PRIORITIES
Definition: test_pbx.c:48
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
const int priorities[MAX_PRIORITIES]
The priorities to register.
Definition: test_pbx.c:108
int pbx_set_extenpatternmatchnew(int newval)
Definition: pbx.c:4781
const char * ast_get_extension_cidmatch(struct ast_exten *e)
Definition: pbx.c:8591
Core PBX routines and definitions.
const char * test_exten
Test extension number.
Definition: test_pbx.c:128
#define AST_TEST_UNREGISTER(cb)
Definition: test.h:128
def info(msg)
const char * ast_get_extension_name(struct ast_exten *exten)
Definition: pbx.c:8548
struct ast_context * contexts
Definition: extconf.c:4483
const int num_priorities
Number of priorities.
Definition: test_pbx.c:95
static char * registrar
Definition: pbx_ael.c:78
static void * cleanup(void *unused)
Definition: pbx_realtime.c:124
an extension to add to our context
Definition: test_pbx.c:53
int ast_add_extension(const char *context, int replace, const char *extension, int priority, const char *label, const char *callerid, const char *application, void *data, void(*datad)(void *), const char *registrar)
Add and extension to an extension context.
Definition: pbx.c:6970
Definition: test.c:65
const char * context
Test context.
Definition: test_pbx.c:118
void ast_context_destroy(struct ast_context *con, const char *registrar)
Destroy a context (matches the specified context or ANY context if NULL)
Definition: conf2ael.c:625
const char * exten
Extension pattern.
Definition: test_pbx.c:73
struct ast_context * ast_context_find_or_create(struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *name, const char *registrar)
Register a new context or find an existing one.
Definition: pbx.c:6198
static int test_exten(const struct pbx_test_pattern *test_pattern, struct ast_test *test, int new_engine)
Definition: test_pbx.c:156
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
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
const int priority
The priority to find.
Definition: test_pbx.c:142
ast_test_result_state
Definition: test.h:200