diff options
author | mmichelson <mmichelson@f38db490-d61c-443f-a65b-d21fe96a405b> | 2010-02-16 18:29:42 +0000 |
---|---|---|
committer | mmichelson <mmichelson@f38db490-d61c-443f-a65b-d21fe96a405b> | 2010-02-16 18:29:42 +0000 |
commit | d3b43c06508c4cf8aa7b497bb7582c557c1bd989 (patch) | |
tree | 83b1e4306b2b482357a2ae5eadabd52dfd010fc3 /tests | |
parent | 80f73350ff5afa2915b87db3db19425be4dc5ea2 (diff) |
Add unit test for dialplan pattern matching.
This test works by reading input from arrays to build a sample
dialplan. From there, patterns are attempted to be matched against
said dialplan, with the expected match given. We then search in our
example dialplan to see if we find a match and if what we find matches
what we expected it to match.
(closes issue #16809)
Reported by: lmadsen
Tested by: mmichelson
Review: https://reviewboard.asterisk.org/r/504/
git-svn-id: http://svn.digium.com/svn/asterisk/trunk@246942 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'tests')
-rw-r--r-- | tests/test_pbx.c | 330 |
1 files changed, 330 insertions, 0 deletions
diff --git a/tests/test_pbx.c b/tests/test_pbx.c new file mode 100644 index 000000000..af2375601 --- /dev/null +++ b/tests/test_pbx.c @@ -0,0 +1,330 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2010, Digium, Inc. + * + * Mark Michelson <mmichelson@digium.com> + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! \file + * + * \brief PBX Tests + * + * \author Mark Michelson <mmichelson@digium.com> + * + * This module will run some PBX tests. + * \ingroup tests + */ + +/*** MODULEINFO + <depend>TEST_FRAMEWORK</depend> + ***/ + +#include "asterisk.h" +#include "asterisk/module.h" +#include "asterisk/pbx.h" +#include "asterisk/test.h" + +/*! + * If we determine that we really need + * to be able to register more than 10 + * priorities for a single extension, then + * fine, we can do that later. + */ +#define MAX_PRIORITIES 10 + +/*! + * \brief an extension to add to our context + */ +struct exten_info { + /*! + * \brief Context + * + * \details + * The extension specified will be added to + * this context when it is created. + */ + const char *context; + /*! + * \brief Extension pattern + * + * \details + * The extension pattern to use. This can be + * anything you would normally find in a dialplan, + * such as "1000" or "NXXNXXX" or whatever you + * wish it to be. If, however, you want a CID match + * to be part of the extension, do not include that + * here. + */ + const char *exten; + /*! + * \brief CID match + * + * \details + * If your extension requires a specific caller ID in + * order to match, place that in this field. Note that + * a NULL and an empty CID match are two very different + * things. If you want no CID match, leave this NULL. If + * you want to explicitly match a blank CID, then put + * an empty string here. + */ + const char *cid; + /*! + * \brief Number of priorities + * + * \details + * Tell the number of priorities to register for this + * extension. All priorities registered will just have a + * Noop application with the extension pattern as its + * data. + */ + const int num_priorities; + /*! + * \brief The priorities to register + * + * \details + * In most cases, when registering multiple priorities for + * an extension, we'll be starting at priority 1 and going + * sequentially until we've read num_priorities. However, + * for some tests, it may be beneficial to start at a higher + * priority or skip certain priorities. This is why you have + * the freedom here to specify which priorities to register + * for the extension. + */ + const int priorities[MAX_PRIORITIES]; +}; + +struct pbx_test_pattern { + /*! + * \brief Test context + * + * \details + * This is the context to look in for a specific extension. + */ + const char *context; + /*! + * \brief Test extension number + * + * \details + * This should be in the form of a specific number or string. + * For instance, if you were trying to match an extension defined + * with the pattern "_2." you might have as the test_exten one of + * "2000" , "2legit2quit" or some other specific match for the pattern. + */ + const char *test_exten; + /*! + * \brief Test CID match + * + * \details + * If a specific CID match is required for pattern matching, then specify + * it in this parameter. Remember that a NULL CID and an empty CID are + * interpreted differently. For no CID match, leave this NULL. If you wish + * to explicitly match an empty CID, then use an empty string here. + */ + const char *test_cid; + /*! + * \brief The priority to find + */ + const int priority; + /*! + * \brief Expected extension match. + * + * \details + * This struct corresponds to an extension that was previously + * added to our test context. Once we have used all the above data + * to find an extension in the dialplan. We compare the data from that + * extension to the data that we have stored in this structure to be + * sure that what was matched was what we expected to match. + */ + const struct exten_info *exten; +}; + +static int test_exten(const struct pbx_test_pattern *test_pattern, struct ast_test *test) +{ + struct pbx_find_info pfi = { { 0 }, }; + struct ast_exten *exten; + if (!(exten = pbx_find_extension(NULL, NULL, &pfi, test_pattern->context, + test_pattern->test_exten, test_pattern->priority, NULL, + test_pattern->test_cid, E_MATCH))) { + ast_test_status_update(test, "Cannot find extension %s in context %s." + "Test failed.\n", test_pattern->test_exten, test_pattern->context); + return -1; + } + if (strcmp(ast_get_extension_name(exten), test_pattern->exten->exten)) { + ast_test_status_update(test, "Expected extension %s but got extension %s instead." + "Test failed.\n", test_pattern->exten->exten, ast_get_extension_name(exten)); + return -1; + } + if (test_pattern->test_cid && strcmp(ast_get_extension_cidmatch(exten), test_pattern->test_cid)) { + ast_test_status_update(test, "Expected CID match %s but got CID match %s instead." + "Test failed.\n", test_pattern->exten->cid, ast_get_extension_cidmatch(exten)); + return -1; + } + ast_test_status_update(test, "Successfully matched %s to exten %s in context %s\n", + test_pattern->test_exten, test_pattern->exten->exten, test_pattern->context); + return 0; +} + +AST_TEST_DEFINE(pattern_match_test) +{ + static const char registrar[] = "test_pbx"; + enum ast_test_result_state res = AST_TEST_PASS; + static const char TEST_PATTERN[] = "test_pattern"; + static const char TEST_PATTERN_INCLUDE[] = "test_pattern_include"; + int i; + + /* The array of contexts to register for our test. + * To add more contexts, just add more rows to this array. + */ + struct { + const char * context_string; + struct ast_context *context; + } contexts[] = { + { TEST_PATTERN, }, + { TEST_PATTERN_INCLUDE, }, + }; + + /* + * Map to indicate which contexts should be included inside + * other contexts. The first context listed will include + * the second context listed. + * + * To add more inclusions, add new rows to this array. + */ + const struct { + const char *outer_context; + const char *inner_context; + } context_includes[] = { + { TEST_PATTERN, TEST_PATTERN_INCLUDE }, + }; + + /* The array of extensions to add to our test context. + * For more information about the individual fields, see + * the doxygen for struct exten_info. + * + * To add new extensions to the test, simply add new rows + * to this array. All extensions will automatically be + * added when the test is run. + */ + const struct exten_info extens[] = { + [0] = { TEST_PATTERN, "_2.", NULL, 1, { 1 } }, + [1] = { TEST_PATTERN, "2000", NULL, 1, { 1 } }, + [2] = { TEST_PATTERN_INCLUDE, "2000", NULL, 1, { 2 } }, + }; + + /* This array contains our test material. See the doxygen + * for struct pbx_test_pattern for more information on each + * component. + * + * To add more test cases, add more lines to this array. Each + * case will be tested automatically when the test is run. + */ + const struct pbx_test_pattern tests[] = { + { TEST_PATTERN, "200", NULL, 1, &extens[0] }, + { TEST_PATTERN, "2000", NULL, 1, &extens[1] }, + { TEST_PATTERN, "2000", NULL, 2, &extens[2] }, + { TEST_PATTERN_INCLUDE, "2000", NULL, 2, &extens[2] }, + }; + + switch (cmd) { + case TEST_INIT: + info->name = "pattern_match_test"; + info->category = "main/pbx/"; + info->summary = "Test pattern matching"; + info->description = "Create a context with a bunch of extensions within. Then attempt\n" + "to match some strings to the extensions."; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + /* Step one is to build the dialplan. + * + * We iterate first through the contexts array to build + * all the contexts we'll need. Then, we iterate over the + * extens array to add all the extensions to the appropriate + * contexts. + */ + + for (i = 0; i < ARRAY_LEN(contexts); ++i) { + if (!(contexts[i].context = ast_context_find_or_create(NULL, NULL, contexts[i].context_string, registrar))) { + ast_test_status_update(test, "Failed to create context %s\n", contexts[i].context_string); + res = AST_TEST_FAIL; + goto cleanup; + } + } + + for (i = 0; i < ARRAY_LEN(context_includes); ++i) { + if (ast_context_add_include(context_includes[i].outer_context, + context_includes[i].inner_context, registrar)) { + ast_test_status_update(test, "Failed to include context %s inside context %s\n", + context_includes[i].inner_context, context_includes[i].outer_context); + res = AST_TEST_FAIL; + goto cleanup; + } + } + + for (i = 0; i < ARRAY_LEN(extens); ++i) { + int priority; + if (extens[i].num_priorities > MAX_PRIORITIES) { + ast_test_status_update(test, "Invalid number of priorities specified for extension %s." + "Max is %d, but we requested %d. Test failed\n", + extens[i].exten, MAX_PRIORITIES, extens[i].num_priorities); + res = AST_TEST_FAIL; + goto cleanup; + } + for (priority = 0; priority < extens[i].num_priorities; ++priority) { + if (ast_add_extension(extens[i].context, 0, extens[i].exten, extens[i].priorities[priority], + NULL, extens[i].cid, "Noop", (void *) extens[i].exten, NULL, registrar)) { + ast_test_status_update(test, "Failed to add extension %s, priority %d, to context %s." + "Test failed\n", extens[i].exten, extens[i].priorities[priority], extens[i].context); + res = AST_TEST_FAIL; + goto cleanup; + } + } + } + + /* At this stage, the dialplan is built. Now we iterate over + * the tests array to attempt to find each of the specified + * extensions. + */ + for (i = 0; i < ARRAY_LEN(tests); ++i) { + if (test_exten(&tests[i], test)) { + res = AST_TEST_FAIL; + break; + } + } + +cleanup: + for (i = 0; i < ARRAY_LEN(contexts); ++i) { + if (contexts[i].context) { + ast_context_destroy(contexts[i].context, registrar); + } + } + + return res; +} + +static int unload_module(void) +{ + AST_TEST_UNREGISTER(pattern_match_test); + return 0; +} + +static int load_module(void) +{ + AST_TEST_REGISTER(pattern_match_test); + return AST_MODULE_LOAD_SUCCESS; +} + +AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "PBX test module"); |