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