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