Asterisk - The Open Source Telephony Project GIT-master-2de1a68
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 <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
19/*! \file
20 *
21 * \brief PBX Tests
22 *
23 * \author Mark Michelson <mmichelson@digium.com>
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 */
53struct 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
156static 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
188AST_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
320cleanup:
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
346AST_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
366AST_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
387{
388 switch (cmd) {
389 case TEST_INIT:
390 info->name = "JUST_FAIL";
391 info->category = "/TEST_PASS_FAIL/";
392 info->summary = "Just fails";
393 info->description = "Just fails. "
394 "This test is mainly used for testing CI and tool failure scenarios.";
395 info->explicit_only = 1;
396 return AST_TEST_NOT_RUN;
397 case TEST_EXECUTE:
398 break;
399 }
400 ast_test_status_update(test, "This test just forces a fail\n");
401
402 return AST_TEST_FAIL;
403}
404
406{
407 switch (cmd) {
408 case TEST_INIT:
409 info->name = "JUST_PASS";
410 info->category = "/TEST_PASS_FAIL/";
411 info->summary = "Just passes";
412 info->description = "Just passes. "
413 "This test is mainly used for testing CI and tool failure scenarios.";
414 info->explicit_only = 1;
415 return AST_TEST_NOT_RUN;
416 case TEST_EXECUTE:
417 break;
418 }
419 ast_test_status_update(test, "This test just forces a pass\n");
420
421 return AST_TEST_PASS;
422}
423
424static int unload_module(void)
425{
426 AST_TEST_UNREGISTER(just_pass);
427 AST_TEST_UNREGISTER(just_fail);
428 AST_TEST_UNREGISTER(call_backtrace);
429 AST_TEST_UNREGISTER(call_assert);
431 AST_TEST_UNREGISTER(pattern_match_test);
432 return 0;
433}
434
435static int load_module(void)
436{
437 AST_TEST_REGISTER(pattern_match_test);
438 AST_TEST_REGISTER(segv);
439 AST_TEST_REGISTER(call_assert);
440 AST_TEST_REGISTER(call_backtrace);
441 AST_TEST_REGISTER(just_fail);
442 AST_TEST_REGISTER(just_pass);
444}
445
int extens
Definition: ael_main.c:93
Asterisk main include file. File version handling, generic pbx functions.
static int priority
@ E_MATCH
Definition: extconf.h:217
void ast_log_backtrace(void)
Log a backtrace of the current thread's execution stack to the Asterisk log.
Definition: logger.c:2498
Asterisk module definitions.
#define AST_MODULE_INFO_STANDARD(keystr, desc)
Definition: module.h:567
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
@ AST_MODULE_LOAD_SUCCESS
Definition: module.h:70
def info(msg)
static struct ast_context * contexts
Definition: pbx.c:781
Core PBX routines and definitions.
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:6928
int ast_context_add_include(const char *context, const char *include, const char *registrar)
Add a context include.
Definition: pbx.c:6664
const char * ast_get_extension_cidmatch(struct ast_exten *e)
Definition: pbx.c:8552
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:6149
int pbx_set_extenpatternmatchnew(int newval)
Definition: pbx.c:4777
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:4190
void ast_context_destroy(struct ast_context *con, const char *registrar)
Destroy a context (matches the specified context or ANY context if NULL)
Definition: pbx.c:8221
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 char * ast_get_extension_name(struct ast_exten *exten)
Definition: pbx.c:8509
static char * registrar
Definition: pbx_ael.c:78
static void * cleanup(void *unused)
Definition: pbx_realtime.c:124
#define NULL
Definition: resample.c:96
ast_exten: An extension The dialplan is saved as a linked list with each context having it's own link...
Definition: pbx.c:237
char * exten
Definition: pbx.c:238
an extension to add to our context
Definition: test_pbx.c:53
const int num_priorities
Number of priorities.
Definition: test_pbx.c:95
const char * exten
Extension pattern.
Definition: test_pbx.c:73
const char * context
Context.
Definition: test_pbx.c:61
const int priorities[MAX_PRIORITIES]
The priorities to register.
Definition: test_pbx.c:108
const char * cid
CID match.
Definition: test_pbx.c:85
const struct exten_info * exten
Expected extension match.
Definition: test_pbx.c:153
const int priority
The priority to find.
Definition: test_pbx.c:142
const char * test_cid
Test CID match.
Definition: test_pbx.c:138
const char * context
Test context.
Definition: test_pbx.c:118
const char * test_exten
Test extension number.
Definition: test_pbx.c:128
Test Framework API.
@ TEST_INIT
Definition: test.h:200
@ TEST_EXECUTE
Definition: test.h:201
#define AST_TEST_REGISTER(cb)
Definition: test.h:127
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
#define AST_TEST_UNREGISTER(cb)
Definition: test.h:128
ast_test_result_state
Definition: test.h:193
@ AST_TEST_PASS
Definition: test.h:195
@ AST_TEST_FAIL
Definition: test.h:196
@ AST_TEST_NOT_RUN
Definition: test.h:194
static int test_exten(const struct pbx_test_pattern *test_pattern, struct ast_test *test, int new_engine)
Definition: test_pbx.c:156
#define MAX_PRIORITIES
Definition: test_pbx.c:48
static int load_module(void)
Definition: test_pbx.c:435
static int unload_module(void)
Definition: test_pbx.c:424
AST_TEST_DEFINE(pattern_match_test)
Definition: test_pbx.c:188
#define ast_assert(a)
Definition: utils.h:739
#define ARRAY_LEN(a)
Definition: utils.h:666