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